Notebook to make the panels for the paper figures after revision

General Setup

Setup chunk

Load libraries

knitr::opts_chunk$set(fig.width = 8)
knitr::opts_knit$set(root.dir = normalizePath(".."))
knitr::opts_knit$get("root.dir")
[1] "/nas/groups/treutlein/USERS/tomasgomes/projects/liver_regen"

Define plot theme(s)

library(dplyr)

Attaching package: ‘dplyr’

The following objects are masked from ‘package:stats’:

    filter, lag

The following objects are masked from ‘package:base’:

    intersect, setdiff, setequal, union
library(Seurat)
Attaching SeuratObject
library(ggplot2)
library(ggrepel)
library(ggridges)
library(pheatmap)
library(RColorBrewer)
library(MetBrewer)

Useful functions

th_gen = theme(axis.text = element_text(size = 7, colour = "black"),
               axis.title = element_text(size = 8, colour = "black"),
               axis.line = element_line(colour = "black"),
               plot.background = element_blank(),
               axis.ticks = element_blank(), 
               panel.background = element_blank(),
               panel.grid = element_blank(),
               legend.background = element_blank(), 
               legend.key.size = unit(0.35, "cm"),
               legend.key = element_blank(), legend.spacing = unit(0.7, "cm"),
               legend.text = element_text(size = 9),
               legend.title = element_text(size = 10),
               legend.box.margin = margin(0.1,0.1,0.1,0.1),
               legend.box.spacing = unit(0.5,"cm"))
pointsize = 0.3
theme_set(th_gen)

Colour palettes

breakStr = function(s, n = 20) {return(gsub(paste0('(.{1,',as.character(n),'})(\\s|$)'), '\\1\n', s))}

getTopTerms = function(godf, topt = 100, ncl = 5, nt = 2){
  topt = if(nrow(godf)<topt) nrow(godf) else topt
  if(nrow(godf)<ncl) return(godf)
  df = godf[1:topt,]
  genes = sapply(df$geneID, function(x) strsplit(x, "/"))
  resmat = matrix(0, length(genes), length(genes))
  for(i in 1:length(genes)){
    for(j in 1:length(genes)){
      resmat[i,j] = length(intersect(genes[[i]], genes[[j]]))/length(genes[[i]])
    }
  }
  cl = hclust(dist(resmat), method = "ward.D2")
  cl = cutree(cl, ncl)
  res_df = data.frame("Description" = df$Description, "qvalue" = df$qvalue, cl, 
                      "geneID" = unlist(df$geneID), stringsAsFactors = F)
  res_df = res_df[order(res_df$qvalue, decreasing = F),]
  topterms = unlist(tapply(res_df$Description, res_df$cl, function(x) x[1:nt]))
  res_df = res_df[res_df$Description %in% topterms,]
  
  return(res_df)
}

getTopTermsPaired = function(godf, genescol = "genes_all", ncl = 5, nt = 2){
  if(nrow(godf)<ncl) return(godf)
  genes = sapply(godf[,genescol], function(x) strsplit(x, "/"))
  resmat = matrix(0, length(genes), length(genes))
  for(i in 1:length(genes)){
    for(j in 1:length(genes)){
      resmat[i,j] = length(intersect(genes[[i]], genes[[j]]))/length(genes[[i]])
    }
  }
  cl = hclust(dist(resmat), method = "ward.D2")
  cl = cutree(cl, ncl)
  res_df = data.frame("Description" = godf$Description, "qval_embolized" = godf$qval_embolized, 
                      "qval_regenerating" = godf$qval_regenerating, 
                      "genes_embolized" = unlist(godf$genes_embolized), 
                      "genes_regenerating" = unlist(godf$genes_regenerating),
                      cl, stringsAsFactors = F)
  res_df$qval_max = apply(res_df[,c("qval_embolized","qval_regenerating")], 1, function(x) min(x))
  res_df = res_df[order(res_df$qval_max, decreasing = F),]
  topterms = unlist(tapply(res_df$Description, res_df$cl, function(x) x[1:nt]))
  res_df = res_df[res_df$Description %in% topterms,]
  
  return(res_df)
}

rpfilter = function(x){
  return(!grepl("^RPL", x$geneID) & !grepl("^RPS", x$geneID) & 
           !grepl("/RPL", x$geneID, fixed = T) & !grepl("/RPS", x$geneID, fixed = T))
}

Figure 1

Main Figure

UMAP with all cell types

colsmajor = c("Cholangiocytes" = "bisque2", "Endothelial" = "aquamarine4",  
              "Hepatocytes" = "tomato3", "Immune" = "skyblue", 
              "Mesenchymal" = "sandybrown", "Doublets" = "grey90")
colcond = c("healthy" = "orange", "regenerating" = "salmon", 
            "embolised" = "darkred", "embolized" = "darkred")
coldon = c("sc_H1" = "plum4", "sc_H2" = "salmon4", "sc_H3" = "lightsalmon3")
coldonall = c("sc_H1" = "plum4", "sc_H2" = "salmon4", "sc_H3" = "lightsalmon3", 
              "sc_E1" = "darkorange3", "sc_R1" = "darkorange3", "sc_E2" = "goldenrod3", 
              "sc_R2" = "goldenrod3",  "sc_E3" = "mediumorchid", "sc_R3" = "mediumorchid", 
              "sc_E4" = "plum2", "sc_R4" = "plum2", "sc_E5" = "palevioletred3", 
              "sc_R5" = "palevioletred3", "sc_E6" = "peachpuff2", "sc_R6" = "peachpuff2",
              "sc_E1/sc_R1" = "darkorange3", "sc_E2/sc_R2" = "goldenrod3", 
              "sc_E3/sc_R3" = "mediumorchid", "sc_E4/sc_R4" = "plum2", 
              "sc_E5/sc_R5" = "palevioletred3", "sc_E6/sc_R6" = "peachpuff2")

colsallct = c("Cholangiocytes" = "bisque2", "Hepatocytes" = "tomato3", "Stellate cells" = "sandybrown", 
              "Doublets" = "grey90", "LSEC pericentral" = "aquamarine4", "LSEC periportal" = "aquamarine2", 
              "Endothelial cells (non-LSEC)" = "forestgreen", "Plasmablasts" = "darkorchid4",
              "Kupffer cells" = "skyblue1", "ab-T cells" = "lightskyblue3", "gd-T cells" = "cornflowerblue",
              "B cells" = "darkorchid1", "cDCs" = "deepskyblue1", "pDCs" = "royalblue3", 
              "Macrophages" = "steelblue3", "Dividing cells" = "grey35", "LSEC" = "aquamarine3")
colsub = c("rosybrown4","thistle4","thistle3","aquamarine4","aquamarine3",
           "forestgreen","tomato4","tomato3","darksalmon","skyblue",
           "cadetblue","sandybrown","palegoldenrod")
colsmidct = c("Cholangiocytes" = "bisque2", "Hepatocytes" = "tomato3", 
              "Mesenchymal" = "sandybrown", "pDCs" = "royalblue3", 
              "T cells" = "lightskyblue3", "LSEC" = "aquamarine3",
              "other ECs" = "forestgreen", "B cells" = "darkorchid1",
              "Kupffer cells" = "skyblue1", "other Mono-Mac" = "steelblue3", 
              "ILC" = "slateblue1")
plot_df = data.frame(hcells_css@reductions$umap_css@cell.embeddings)
plot_df$names_major = as.character(hcells_css@meta.data$names_major)
plot_df$names_major[plot_df$names_major=="T cells" | 
                      plot_df$names_major=="B cells" | 
                      plot_df$names_major=="Macrophages" |
                      plot_df$names_major=="DCs"] = "Immune"
plot_df$names_major[plot_df$names_major=="Stellate cells"] = "Mesenchymal"
plot_df$names_major[plot_df$names_major=="Endothelial cells"] = "Endothelial"
plt = ggplot(plot_df, aes(x = UMACSS_1, y = UMACSS_2, colour = names_major))+
  geom_point(size = pointsize)+
  guides(colour = guide_legend(override.aes = list(size = 3), title = "Cell Type"))+
  scale_colour_manual(values = colsmajor)+
  theme_classic()+
  th_gen+
  theme(axis.line = element_blank(),
        axis.ticks = element_blank(),
        axis.title = element_blank(),
        axis.text = element_blank(),
        legend.title = element_text(hjust = 0),
        aspect.ratio = 1)

pdf("figure_panels/fig1/umap_fresh_major.pdf", 
    useDingbats = F, height = 4, width = 5)
print(plt)
dev.off()
png("figure_panels/fig1/umap_fresh_major.png", 
    height=8, width=8, unit="cm", res=600, antialias = "subpixel")
print(plt)
dev.off()
pdf("figure_panels/fig1/umap_fresh_major_noLeg.pdf", 
    useDingbats = F, height = 4, width = 5)
print(plt+theme(legend.position = "none"))
dev.off()
png("figure_panels/fig1/umap_fresh_major_noLeg.png", 
    height=8, width=8, unit="cm", res=600, antialias = "subpixel")
print(plt+theme(legend.position = "none"))

UMAP with healthy donors

plot_df = data.frame(hcells_css@reductions$umap_css@cell.embeddings)
plot_df$Donor = factor(hcells_css@meta.data$Donor)
plot_df$Donor = plyr::revalue(plot_df$Donor, c("HD1" = "sc_H1", "HD2" = "sc_H2", "HD3" = "sc_H3"))

plt = ggplot(plot_df[sample(1:nrow(plot_df), nrow(plot_df), replace = F),], 
             aes(x = UMACSS_1, y = UMACSS_2, colour = Donor))+
  geom_point(size = pointsize)+
  guides(colour = guide_legend(override.aes = list(size = 3), title = "Donors"))+
  scale_colour_manual(values = coldon)+
  theme_classic()+
  th_gen+
  theme(axis.line = element_blank(),
        axis.ticks = element_blank(),
        axis.title = element_blank(),
        axis.text = element_blank(),
        legend.title = element_text(hjust = 0),
        aspect.ratio = 1)

pdf("figure_panels/fig1/umap_fresh_donors.pdf", 
    useDingbats = F, height = 4, width = 5)
print(plt)
dev.off()
png("figure_panels/fig1/umap_fresh_donors.png", 
    height=8, width=8, unit="cm", res=600, antialias = "subpixel")
print(plt)
dev.off()
pdf("figure_panels/fig1/umap_fresh_donors_noLeg.pdf", 
    useDingbats = F, height = 4, width = 5)
print(plt+theme(legend.position = "none"))
dev.off()
png("figure_panels/fig1/umap_fresh_donors_noLeg.png", 
    height=8, width=8, unit="cm", res=600, antialias = "subpixel")
print(plt+theme(legend.position = "none"))
dev.off()

Violins for cell type markers

markers = c("ASGR1", "APOB", "APOC3",
            "KRT7","CLDN4","EPCAM",
            "CLEC4G","PECAM1","CD36",
            "DCN","COLEC11","ACTA2",
            "PTPRC","HLA-DQA1","LYZ")
exp_mk = data.frame(Matrix::t(hcells_css@assays$SCT@data[markers,]))
plot_df = cbind(exp_mk, 
                data.frame(names_major = as.character(hcells_css@meta.data[,c("names_major")]), 
                           stringsAsFactors = F))
plot_df$names_major[plot_df$names_major=="T cells" | 
                      plot_df$names_major=="B cells" | 
                      plot_df$names_major=="Macrophages" | 
                      plot_df$names_major=="DCs"] = "Immune"
plot_df$names_major[plot_df$names_major=="Endothelial cells"] = "Endothelial"
plot_df$names_major[plot_df$names_major=="Stellate cells"] = "Mesenchymal"
plot_df = plot_df[plot_df$names_major!="Doublets",]
plot_df$names_major = factor(plot_df$names_major, 
                             levels = c("Hepatocytes", "Cholangiocytes", "Endothelial", "Mesenchymal",
                                        "Immune"))
plot_df = reshape2::melt(plot_df)
plot_df$variable = factor(gsub(".", "-", plot_df$variable, fixed = T), levels = markers)

vio_mk = ggplot(plot_df, aes(x = names_major, y = value, fill = names_major))+
  facet_grid(variable~names_major, scales = "free")+
  geom_violin(scale = "width", size = 0.3)+
  scale_y_continuous(breaks = seq(0,10,2), labels = seq(0,10,2), name = "log(exp+1)")+
  scale_fill_manual(values = colsmajor)+
  theme(strip.background.y = element_blank(),
        strip.background.x = element_rect(fill = "transparent", 
                                          colour = "black", size = 0.8),
        strip.text.y = element_text(angle = 0, size = 6.5, colour = "black", face = "bold"),
        strip.text.x = element_text(face = "bold", size = 6.5, colour = "black"),
        legend.position = "none",
        axis.text.x = element_blank(),
        axis.title.x = element_blank(), 
        axis.line.x.bottom = element_blank())

pdf("figure_panels/fig1/violin_markers_major.pdf", 
    useDingbats = F, height = 5, width = 5.5)
print(vio_mk)
dev.off()
png("figure_panels/fig1/violin_markers_major.png", height = 425, width = 450, antialias = "subpixel")
print(vio_mk)
dev.off()

Heatmap for major cell types

# removed HHIP
nmg=c("PDGFRA","CALD1","COL6A1","PDGFRB",
      "CSF1R","CD163","MARCO","CD69","IL7R","PCK1","CYP2A7","CYP3A4","CRP",
      "ROBO4","EGFL7","CLEC4M","FCN2","KRT7","CFTR","ONECUT1")
plot_df = data.frame(row.names = rownames(hcells_css@meta.data),
                     names_major = as.character(hcells_css@meta.data[,c("names_major")]),
                     donor = as.character(hcells_css@meta.data[,c("Donor")]),
                     stringsAsFactors = F) 
plot_df$names_major[plot_df$names_major=="T cells" | 
                      plot_df$names_major=="B cells" | 
                      plot_df$names_major=="Macrophages" | 
                      plot_df$names_major=="DCs"] = "Immune"
plot_df$names_major[plot_df$names_major=="Endothelial cells"] = "Endothelial"
plot_df$names_major[plot_df$names_major=="Stellate cells"] = "Mesenchymal"
plot_df = plot_df[plot_df$names_major!="Doublets",]
plot_df = plot_df[order(plot_df$names_major),]
m1=GetAssayData(hcells_css, slot="data")[nmg,rownames(plot_df)]
m1 = t(apply(m1, 1, scale, scale = F))
colnames(m1)=rep("",ncol(m1))
coul <- colorRampPalette(brewer.pal(9, "Greys"))(100)[-c(1:5)]
m1[m1>1] = 1
#m1[m1<=(-2)] = -2
heatmap(m1,Rowv = NA,Colv = NA, col=coul)

Violins for all cell types

exp_mk = data.frame(Matrix::t(hcells_css@assays$SCT@data[markers,]))
plot_df = cbind(exp_mk, 
                hcells_css@meta.data[,c("names_major","names_clusters")])
plot_df$names_major = as.character(plot_df$names_major)
plot_df$names_major[plot_df$names_major=="T cells" | 
                      plot_df$names_major=="B cells" | 
                      plot_df$names_major=="Macrophages" | 
                      plot_df$names_major=="DCs"] = "Immune"
plot_df$names_major[plot_df$names_major=="Endothelial cells"] = "Endothelial"
plot_df$names_major[plot_df$names_major=="Stellate cells"] = "Mesenchymal"
plot_df = plot_df[plot_df$names_major!="Doublets",]
plot_df$names_major = factor(plot_df$names_major, 
                             levels = c("Hepatocytes", "Cholangiocytes", "Endothelial", "Mesenchymal",
                                        "Immune"))
plot_df = reshape2::melt(plot_df)
plot_df$variable = factor(gsub(".", "-", plot_df$variable, fixed = T), levels = markers)

ggplot(plot_df, aes(x = names_clusters, y = value, fill = names_clusters))+
  facet_grid(variable~names_major, scales = "free")+
  geom_violin(scale = "width")+
  scale_y_continuous(breaks = seq(0,10,2), labels = seq(0,10,2), name = "log(exp+1)")+
  #scale_fill_manual(values = colsmajor)+
  theme(strip.background.y = element_blank(),
        strip.background.x = element_rect(fill = "transparent", 
                                          colour = "black", size = 0.8),
        strip.text.y = element_text(angle = 0, size = 6.5, colour = "black", face = "bold"),
        strip.text.x = element_text(face = "bold", size = 6.5, colour = "black"),
        legend.position = "none",
        axis.text.x = element_text(angle = -35, hjust = 0, vjust = 0.1),
        axis.line.x.bottom = element_blank())

Cell type proportions

plot_df = data.frame("names_major" = as.character(hcells_css@meta.data$names_major),
                     "Donor" = as.character(hcells_css@meta.data$Donor),
                     stringsAsFactors = F)
plot_df$names_major[plot_df$names_major=="T cells" | 
                      plot_df$names_major=="B cells" | 
                      plot_df$names_major=="Macrophages" | 
                      plot_df$names_major=="DCs"] = "Immune"
plot_df$names_major[plot_df$names_major=="Endothelial cells"] = "Endothelial"
plot_df$names_major[plot_df$names_major=="Stellate cells"] = "Mesenchymal"
plot_df = plot_df[plot_df$names_major!="Doublets",]
cnts_ct = table(plot_df$names_major, plot_df$Donor)
plot_df = reshape2::melt(apply(cnts_ct, 1, function(x) x/sum(x)))
#plot_df$Var2 = factor(plot_df$Var2, 
#                      levels = c("Hepatocytes", "Cholangiocytes", "Endothelial","Mesenchymal", "Immune"))
plot_df$Var1 = plyr::revalue(plot_df$Var1, c("HD1" = "sc_H1", "HD2" = "sc_H2", "HD3" = "sc_H3"))
plot_df$Var1 = factor(plot_df$Var1, levels = rev(levels(plot_df$Var1)))

plt = ggplot(plot_df, aes(x = Var2, y = value*100, fill = Var1))+
  geom_bar(stat = "identity")+
  scale_y_continuous(expand = c(0,0))+
  scale_fill_manual(values = coldon)+
  labs(y = "Cell type proportion [%]", x = NULL)+
  theme_classic()+
  th_gen+
  theme(axis.line.x = element_blank(),
        axis.ticks.y = element_line(),
        axis.ticks.x = element_blank())

pdf("figure_panels/fig1/proportions_fresh_major_donor.pdf", 
    useDingbats = F, height = 4, width = 5)
print(plt)
dev.off()
png("figure_panels/fig1/proportions_fresh_major_donor.png", 
    height = 325, width = 400, antialias = "subpixel")
print(plt)
dev.off()
pdf("figure_panels/fig1/proportions_fresh_major_donor_noLeg.pdf", 
    useDingbats = F, height = 4, width = 5)
print(plt+theme(legend.position = "none"))
dev.off()
png("figure_panels/fig1/proportions_fresh_major_donor_noLeg.png", 
    height = 325, width = 400, antialias = "subpixel")
print(plt+theme(legend.position = "none"))
dev.off()

Import markers

markers = c("ASGR1", "APOB", "APOC3", "CYP2E1", "HAMP", "ORM1", "SAA1", "NNMT", "FABP1", "MT1G", "ORM2", "TTR", "HP", "APOC1", "APOA2","FGB","CYP3A4","CPS1","ARG1","SAA2",# Hep
            "KRT7","CLDN4","EPCAM", "TACSTD2", "CD24", "KRT19", "ANXA4", "CXCL6", "FXYD2", "SOX4",  "CRYAB","DEFB1","SLC12A2","MMP7","TNFRSF12A","CXCL1","BICC1","S100A14","DCDC2","PLPP2",# Cho
            "CLEC4G","PECAM1","CD36", "FCN3", "DNASE1L3", "CLEC1B", "CRHBP", "AKAP12", "IFI27", "GNG11", "IL33","FLT1","PRSS23","ENG","RAMP3","F8","VWF","CLDN5","CCL14","LYVE1",# End
            "DCN","COLEC11","ACTA2", "CCL2", "TAGLN", "IGFBP3", "BGN", "LUM", "COL3A1", "MYL9", "TPM2","AEBP1","GGT5","ASPN","COL14A1","PTGDS","COL6A1","CYR61","COLEC10","CXCL12",# Mes
            "PTPRC","HLA-DQA1","LYZ", "LILRB2", "MARCO", "C1QB", "FCGR3A",  "NKG7", "MS4A1", "MZB1", "CCL5","KLRD1","AREG","MS4A7","AXL","CD69","GPR183","TLR2","CD44","IL7R") # Imm
mk_list = list("Hepatocytes" = markers[1:10], "Cholangiocytes" = markers[21:30], 
               "Endothelial" = markers[41:50], "Mesenchymal" = markers[61:70], "Immune" = markers[81:90])

cell_type_mk = readRDS(file = "results/integr_allcells/cell_type_mk_major.RDS")
fresh_de = list()
for(n in unique(cell_type_mk$major_all$cluster)){
  fresh_de[[n]] = cell_type_mk$major_all[cell_type_mk$major_all$cluster==n,]
}

load("data/processed/received_Aga/DE_tables_celltype_frozenSCT.rdata")
frozen_de = list("Cholangiocytes" = cell_type_mk_cho, "Hepatocytes" = cell_type_mk_hep, 
                 "Endothelial" = cell_type_mk_ec, "Immune" = cell_type_mk_imm, 
                 "Mesenchymal" = cell_type_mk_mes)
for(n in names(frozen_de)){
  frozen_de[[n]]$cluster = n
  frozen_de[[n]]$gene = rownames(frozen_de[[n]])
}

both_list = list()
top_mk = list()
for(n in names(fresh_de)){
  both_DE = merge(fresh_de[[n]], frozen_de[[n]], by = "gene", all = T)[,c(1,3,6,9,12)]
  colnames(both_DE) = c("gene", "FC_fresh", "pval_fresh", "FC_frozen", "pval_frozen")
  both_DE$FC_fresh[is.na(both_DE$FC_fresh)] = 0
  both_DE$pval_fresh[is.na(both_DE$pval_fresh)] = 1
  both_DE$FC_frozen[is.na(both_DE$FC_frozen)] = 0
  both_DE$pval_frozen[is.na(both_DE$pval_frozen)] = 1
  both_DE$celltype = n
  both_DE$s = both_DE$FC_fresh+both_DE$FC_frozen
  both_DE = both_DE[order(both_DE$s, decreasing = T),]
  cond_fc = both_DE$FC_fresh>=0.1 & both_DE$FC_frozen>=0.1
  cond_pv = both_DE$pval_fresh<=0.05 | both_DE$pval_frozen<=0.05
  both_DE$iscol = ifelse(cond_fc & cond_pv, 
                         ifelse(both_DE$gene %in% mk_list[[n]], "istop", "isDE"), "notDE")
  both_DE$iscol = factor(both_DE$iscol, levels = rev(c("istop", "isDE", "notDE")))
  both_DE$istop = both_DE$gene %in% mk_list[[n]]#[1:3]
  both_list[[n]] = both_DE
  top_mk[[n]] = both_DE$gene[cond_fc & cond_pv][1:20]
}
top_mk = top_mk[c(4,1,3,5,2)]

Heatmap per cluster

cell_type_mk = readRDS(file = "results/cond_effect/cell_type_mk.RDS")
# cut markers here depending on the size you want for heatmap, then adjust figure
markers = c("ASGR1", "APOB", "APOC3", "CYP2E1", "HAMP", "ORM1", "SAA1", "NNMT", "FABP1", "MT1G", "ORM2", "TTR", "HP", "APOC1", "APOA2","FGB","CYP3A4","CPS1","ARG1","SAA2",# Hep
            "KRT7","CLDN4","EPCAM", "TACSTD2", "CD24", "KRT19", "ANXA4", "CXCL6", "FXYD2", "SOX4",  "CRYAB","DEFB1","SLC12A2","MMP7","TNFRSF12A","CXCL1","BICC1","S100A14","DCDC2","PLPP2",# Cho
            "CLEC4G","PECAM1","CD36", "FCN3", "DNASE1L3", "CLEC1B", "CRHBP", "AKAP12", "IFI27", "GNG11", "IL33","FLT1","PRSS23","ENG","RAMP3","F8","VWF","CLDN5","CCL14","LYVE1",# End
            "DCN","COLEC11","ACTA2", "CCL2", "TAGLN", "IGFBP3", "BGN", "LUM", "COL3A1", "MYL9", "TPM2","AEBP1","GGT5","ASPN","COL14A1","PTGDS","COL6A1","CYR61","COLEC10","CXCL12",# Mes
            "PTPRC","HLA-DQA1","LYZ", "LILRB2", "MARCO", "C1QB", "FCGR3A",  "NKG7", "MS4A1", "MZB1", "CCL5","KLRD1","AREG","MS4A7","AXL","CD69","GPR183","TLR2","CD44","IL7R") # Imm
markers_topboth = unlist(top_mk)
markers = markers_topboth

load("data/processed/received_Aga/mean_exp_celltype_frozen.rdata")
hcells_css@meta.data$major_ct = as.character(hcells_css@meta.data$names_major)
hcells_css@meta.data$major_ct[hcells_css@meta.data$major_ct=="T cells" | 
                      hcells_css@meta.data$major_ct=="B cells" | 
                      hcells_css@meta.data$major_ct=="Macrophages" |
                      hcells_css@meta.data$major_ct=="DCs"] = "Immune"
hcells_css@meta.data$major_ct[hcells_css@meta.data$major_ct=="Stellate cells"] = "Mesenchymal"
hcells_css@meta.data$major_ct[hcells_css@meta.data$major_ct=="Endothelial cells"] = "Endothelial"
m_ct_fresh = apply(as.matrix(hcells_css@assays$SCT@data), 1, 
                   function(x) tapply(x, hcells_css@meta.data$major_ct, mean))

m_ct_frozen = t(m_ct_frozen)
m_ct_frozen = t(apply(m_ct_frozen, 1, scale))
colnames(m_ct_frozen) = rownames(m_ct_fresh)[-2]
m_ct_fresh = t(m_ct_fresh)[,-2]
m_ct_fresh = t(apply(m_ct_fresh, 1, scale))
colnames(m_ct_fresh) = colnames(m_ct_frozen)

mean_ct = merge(m_ct_fresh, m_ct_frozen, by = 0)
rownames(mean_ct) = mean_ct[,1]
mean_ct = mean_ct[,-1]
colnames(mean_ct) = paste0(rep(colnames(m_ct_fresh), 2), rep(c("_fresh", "_frozen"), each = 5))

hcl = hclust(dist(t(mean_ct)), method = "ward.D2")
plot(hcl)

annot_df = data.frame(row.names = colnames(mean_ct),
                      "cell type" = unlist(lapply(strsplit(colnames(mean_ct), "_"), function(x) x[1])),
                      "processing" = unlist(lapply(strsplit(colnames(mean_ct), "_"), function(x) x[2])))

callback = function(hc, mat){
  sv = svd(t(mat))$v[,2]
    dend = reorder(as.dendrogram(hc), c(1:4,))
    as.hclust(dend)
}

pdf("figure_panels/fig1/major_celltypes_heatmap_freshfrozen_10.pdf", 
    useDingbats = F, height = 7.5, width = 6)
heat = pheatmap::pheatmap(mean_ct[markers[c(41:50, 61:70, 81:90,  1:10, 21:30)],], 
                          clustering_method = "ward.D2", treeheight_row = 0, annotation_col = annot_df,
                          cluster_rows = F, treeheight_col = 20, fontsize_row = 5.5,
                          annotation_colors = list("processing" = c("fresh" = "#d4d4d4", 
                                                                    "frozen" = "#5d5d5d"),
                                                   "cell.type" = colsmajor[-6]),
                          show_colnames = F, 
                          color = colorRampPalette(rev(brewer.pal(n = 9, name = "RdBu")))(100))
dev.off()

FC fresh vs frozen

mk_list = list("Hepatocytes" = markers[1:10], "Cholangiocytes" = markers[21:30], 
               "Endothelial" = markers[41:50], "Mesenchymal" = markers[61:70], "Immune" = markers[81:90])

plt_fc_list = list()
pdf("figure_panels/fig1/major_celltypes_FCscatter_10.pdf", 
    useDingbats = F, height = 5, width = 4.5)
for(n in names(both_list)){
  both_DE = both_list[[n]]
  cc = cor(both_DE$FC_fresh, both_DE$FC_frozen)
  both_DE = both_DE[order(both_DE$iscol),]
  
  cols_use = c("istop" = unname(colsmajor[n]), "isDE" = "grey35", "notDE" = "grey85")
  plt = ggplot(both_DE, aes(x = FC_fresh, y = FC_frozen, colour = iscol))+
    geom_vline(xintercept = 0, colour = "grey40")+
    geom_hline(yintercept = 0, colour = "grey40")+
    geom_point()+
    geom_text_repel(data = both_DE[both_DE$istop & both_DE$iscol=="istop",], mapping = aes(label = gene),
                    fontface = "bold")+
    theme_bw()+
    scale_colour_manual(values = cols_use)+
    labs(title = n, subtitle = paste0("PCC = ", round(cc, 2)))+
    theme(aspect.ratio = 1,
          axis.text = element_text(colour = "black"),
          legend.position = "none", 
          panel.grid = element_blank())
  
  plt_fc_list[[n]] = plt
  print(plt)
}
dev.off()

Expression comparison fresh vs frozen

load("data/processed/received_Aga/mean_exp_celltype_frozenCOUNTS.rdata")
hcells_css@meta.data$major_ct = as.character(hcells_css@meta.data$names_major)
hcells_css@meta.data$major_ct[hcells_css@meta.data$major_ct=="T cells" | 
                      hcells_css@meta.data$major_ct=="B cells" | 
                      hcells_css@meta.data$major_ct=="Macrophages" |
                      hcells_css@meta.data$major_ct=="DCs"] = "Immune"
hcells_css@meta.data$major_ct[hcells_css@meta.data$major_ct=="Stellate cells"] = "Mesenchymal"
hcells_css@meta.data$major_ct[hcells_css@meta.data$major_ct=="Endothelial cells"] = "Endothelial"
m_ct_fresh = apply(as.matrix(hcells_css@assays$SCT@counts), 1, 
                   function(x) tapply(x, hcells_css@meta.data$major_ct, mean))

m_ct_frozen = log(t(m_ct_frozen.counts))
#m_ct_frozen = t(apply(m_ct_frozen, 1, scale))
colnames(m_ct_frozen) = rownames(m_ct_fresh)[-2]
m_ct_fresh = log(t(m_ct_fresh)[,-2])
#m_ct_fresh = t(apply(m_ct_fresh, 1, scale))
colnames(m_ct_fresh) = colnames(m_ct_frozen)

mean_ct = merge(m_ct_fresh, m_ct_frozen, by = 0)
rownames(mean_ct) = mean_ct[,1]
mean_ct = mean_ct[,-1]
colnames(mean_ct) = paste0(rep(colnames(m_ct_fresh), 2), rep(c("_fresh", "_frozen"), each = 5))

par(mfrow = c(2,3))
plot(mean_ct$Cholangiocytes_fresh, mean_ct$Cholangiocytes_frozen, pch = 20, cex = 0.5, xlim = c(-8,5), ylim = c(-8,5))
title("Cholangiocytes")
abline(0,1)
plot(mean_ct$Endothelial_fresh, mean_ct$Endothelial_frozen, pch = 20, cex = 0.5, xlim = c(-8,5), ylim = c(-8,5))
title("Endothelial")
abline(0,1)
plot(mean_ct$Hepatocytes_fresh, mean_ct$Hepatocytes_frozen, pch = 20, cex = 0.5, xlim = c(-10,6), ylim = c(-10,6))
title("Hepatocytes")
abline(0,1)
plot(mean_ct$Immune_fresh, mean_ct$Immune_frozen, pch = 20, cex = 0.5, xlim = c(-8,5), ylim = c(-8,5))
title("Immune")
abline(0,1)
plot(mean_ct$Mesenchymal_fresh, mean_ct$Mesenchymal_frozen, pch = 20, cex = 0.5, xlim = c(-8,5), ylim = c(-8,5))
title("Mesenchymal")
abline(0,1)
plot(rowMeans(mean_ct[,1:5]), rowMeans(mean_ct[,6:10]), pch = 20, cex = 0.5, xlim = c(-8,5), ylim = c(-8,5))
title("All")
abline(0,1)

Supplementary

UMAP with healthy donors split

plot_df = data.frame(hcells_css@reductions$umap_css@cell.embeddings)
plot_df$Donor = factor(hcells_css@meta.data$Donor)
plot_df$Donor = plyr::revalue(plot_df$Donor, c("HD1" = "sc_H1", "HD2" = "sc_H2", "HD3" = "sc_H3"))

plt = ggplot(plot_df[sample(1:nrow(plot_df), nrow(plot_df), replace = F),], 
             aes(x = UMACSS_1, y = UMACSS_2, colour = Donor))+
  facet_wrap(~Donor)+
  geom_point(size = 0.15)+
  guides(colour = guide_legend(override.aes = list(size = 3), title = "Donors"))+
  scale_colour_manual(values = coldon)+
  theme_classic()+
  th_gen+
  theme(axis.line = element_blank(),
        axis.ticks = element_blank(),
        axis.title = element_blank(),
        axis.text = element_blank(),
        legend.title = element_text(hjust = 0),
        aspect.ratio = 1)

pdf("figure_panels/fig1/umap_fresh_donors_split.pdf", 
    useDingbats = F, height = 4, width = 7)
print(plt)
dev.off()
png("figure_panels/fig1/umap_fresh_donors_split.png", 
    height=8, width=10, unit="cm", res=600, antialias = "subpixel")
print(plt)
dev.off()
pdf("figure_panels/fig1/umap_fresh_donors_noLeg_split.pdf", 
    useDingbats = F, height = 4, width = 7)
print(plt+theme(legend.position = "none"))
dev.off()
png("figure_panels/fig1/umap_fresh_donors_noLeg_split.png", 
    height=8, width=10, unit="cm", res=600, antialias = "subpixel")
print(plt+theme(legend.position = "none"))
dev.off()

Boxplot with nUMI

plot_df = data.frame(hcells_css@reductions$umap_css@cell.embeddings)
plot_df$names_major = as.character(hcells_css@meta.data$names_major)
plot_df$names_major[plot_df$names_major=="T cells" | 
                      plot_df$names_major=="B cells" | 
                      plot_df$names_major=="Macrophages" |
                      plot_df$names_major=="DCs"] = "Immune"
plot_df$names_major[plot_df$names_major=="Stellate cells"] = "Mesenchymal"
plot_df$names_major[plot_df$names_major=="Endothelial cells"] = "Endothelial"
plot_df$nGene = hcells_css@meta.data$nFeature_SCT
plot_df = plot_df[,3:5]
saveRDS(plot_df, "./to_send/df_celltypes_umi_gene.RDS") # plotted by Aga

UMAP with all cell types

plot_df = data.frame(hcells_css@reductions$umap_css@cell.embeddings)
colnames(plot_df) = c("UMAPCSS_1", "UMAPCSS_2")
plot_df$names_major = as.character(hcells_css@meta.data$names_major)
plot_df$names_major[plot_df$names_major=="T cells" | 
                      plot_df$names_major=="B cells" | 
                      plot_df$names_major=="Macrophages" |
                      plot_df$names_major=="DCs"] = "Immune"
plot_df$names_major[plot_df$names_major=="Stellate cells"] = "Mesenchymal"
plot_df$names_major[plot_df$names_major=="Endothelial cells"] = "Endothelial"
plot_df$names_clusters = as.character(hcells_css@meta.data$names_clusters)
plot_df$names_clusters[grepl("Hepatocytes ", plot_df$names_clusters)] = "Hepatocytes"
plot_df$names_clusters[grepl("central vein", plot_df$names_clusters)] = "LSEC pericentral"
plot_df$names_clusters[grepl("portal vein", plot_df$names_clusters)] = "LSEC periportal"
plot_df$names_clusters[grepl("interaction", plot_df$names_clusters) |
                         grepl("mix", plot_df$names_clusters) ] = "Doublets"
plot_df$names_clusters = factor(plot_df$names_clusters, 
                                levels = c("Cholangiocytes", "LSEC periportal", "LSEC pericentral", 
                                           "Endothelial cells (non-LSEC)", "Hepatocytes", "Kupffer cells",
                                           "Macrophages", "cDCs", "pDCs", "ab-T cells", "gd-T cells",
                                           "B cells", "Plasmablasts",
                                           "Stellate cells", "Dividing cells", "Doublets"))

pltumap = ggplot(plot_df, aes(y = UMAPCSS_2, x = UMAPCSS_1, colour = names_clusters))+
  geom_point(size = pointsize)+
  labs(colour = "Cell Type")+
  scale_colour_manual(values = c(colsallct, "Other" = "grey88"))+
  guides(colour = guide_legend(override.aes = list(size = 2)))+
  theme(aspect.ratio = 1,
        legend.title = element_text(hjust = 0),
        axis.line = element_blank(),
        axis.text = element_blank())

pdf("figure_panels/fig1/umap_h_all_celltypes.pdf", height = 5, width = 6, useDingbats = F)
print(pltumap)
dev.off()
png("figure_panels/fig1/umap_h_all_celltypes.png", height = 325, width = 400, antialias = "subpixel")
print(pltumap)
dev.off()

plot_df$names_clusters[plot_df$names_major!="Immune"] = "Doublets"
levels(plot_df$names_clusters)[levels(plot_df$names_clusters)=="Doublets"] = "Other"
pltumap = ggplot(plot_df, aes(y = UMAPCSS_2, x = UMAPCSS_1, colour = names_clusters))+
  geom_point(size = pointsize)+
  labs(colour = "Cell Type")+
  scale_colour_manual(values = c(colsallct, "Other" = "grey88"))+
  guides(colour = guide_legend(override.aes = list(size = 2)))+
  theme(aspect.ratio = 1,
        legend.title = element_text(hjust = 0),
        axis.line = element_blank(),
        axis.text = element_blank())

Heatmap with markers for all cell types

plot_df = data.frame(hcells_css@reductions$umap_css@cell.embeddings)
colnames(plot_df) = c("UMAPCSS_1", "UMAPCSS_2")
plot_df$names_major = as.character(hcells_css@meta.data$names_major)
plot_df$names_major[plot_df$names_major=="T cells" | 
                      plot_df$names_major=="B cells" | 
                      plot_df$names_major=="Macrophages" |
                      plot_df$names_major=="DCs"] = "Immune"
plot_df$names_major[plot_df$names_major=="Stellate cells"] = "Mesenchymal"
plot_df$names_major[plot_df$names_major=="Endothelial cells"] = "Endothelial"
plot_df$names_clusters = as.character(hcells_css@meta.data$names_clusters)
plot_df$names_clusters[grepl("Hepatocytes ", plot_df$names_clusters)] = "Hepatocytes"
plot_df$names_clusters[grepl("central vein", plot_df$names_clusters)] = "LSEC pericentral"
plot_df$names_clusters[grepl("portal vein", plot_df$names_clusters)] = "LSEC periportal"
plot_df$names_clusters[grepl("interaction", plot_df$names_clusters) |
                         grepl("mix", plot_df$names_clusters) ] = "Doublets"
plot_df$names_clusters = factor(plot_df$names_clusters, 
                                levels = c("Cholangiocytes", "LSEC periportal", "LSEC pericentral", 
                                           "Endothelial cells (non-LSEC)", "Hepatocytes", "Kupffer cells",
                                           "Macrophages", "cDCs", "pDCs", "ab-T cells", "gd-T cells",
                                           "B cells", "Plasmablasts",
                                           "Stellate cells", "Dividing cells", "Doublets"))
plot_df = plot_df[plot_df$names_clusters!="Doublets",]

nmg = c("KRT7", "CD24",  "LILRA4", "IRF7",  "FCER1A", "CLEC10A",  "CCL23","CLEC1B",  "INMT","SELP",  
        "MARCO","CD5L",  "CYP2E1","ORM2",  "MS4A1","CD79A",  "CLEC14A","EDNRB",  "IGLC2","CD27",  
        "TRDC","KLRD1",  "TRAC","CD3E",  "DCN","COLEC11",  "S100A12","CD300E")
nmg = nmg[c(1,2,13,14,17,18,7,8,9,10,25,26,27,28,11,12,5,6,3,4,23,24,21,22,15,16,19,20)]

m1 = GetAssayData(hcells_css, slot="data")[nmg,rownames(plot_df)]
m_ct_fresh = apply(m1, 1, function(x) tapply(x, as.character(plot_df$names_clusters), mean))
m_ct_fresh[m_ct_fresh>4] = 4.01
m_ct_fresh[m_ct_fresh<(-4)] = -4.01

annot_df = unique(plot_df[,c(3,4)])
annot_df = data.frame(row.names = annot_df$names_clusters, "ct" = annot_df$names_major)
heat = pheatmap::pheatmap(scale(m_ct_fresh[c(4,7,10,9,5,14,11,8,3,12,1,6,2,13),]), 
                          clustering_method = "ward.D2", treeheight_row = 0,
                          treeheight_col = 20, fontsize_row = 8, fontsize_col = 8,
                          cluster_cols = F, cluster_rows = F,
                          annotation_row = annot_df, annotation_colors = list(ct = colsmajor[-6]),
                          color = colorRampPalette(rev(brewer.pal(n = 9, name = "RdBu")))(100))

pdf("figure_panels/fig1/heatmap_all_celltypes.pdf", height = 3.5, width = 7, useDingbats = F)
print(heat)
dev.off()

Figure 2

Main Figure

UMAP with cell types

allcells_css = readRDS(file = "data/processed/allcells_css_reannot.RDS")

load(file = "data/processed/healthy_srat_beforeFiltering.RData")
load(file = "data/processed/cond_srat_beforeFiltering.RData")
allcells_css = readRDS(file = "data/processed/allcells_css_reannot.RDS")

load(file = "data/processed/healthy_srat_beforeFiltering.RData")
load(file = "data/processed/cond_srat_beforeFiltering.RData")

UMAP with all cell types

plot_df = allcells_css@meta.data
plot_df = cbind(plot_df, allcells_css@reductions$umap_css@cell.embeddings)
plot_df$Condition = factor(plot_df$Condition, levels = c("healthy", "embolised", "regenerating"))
plot_df$allcells_simp[grepl("interaction", plot_df$allcells_simp)] = "Doublets"
plot_df$allcells_simp[grepl("Hepatocytes ", plot_df$allcells_simp)] = "Hepatocytes"
plot_df$allcells_simp = factor(plot_df$allcells_simp, 
                               levels = c("Cholangiocytes", "LSEC periportal", "LSEC pericentral", 
                                          "Endothelial cells (non-LSEC)", "Hepatocytes", "Kupffer cells",
                                          "Macrophages", "cDCs", "pDCs", "ab-T cells", "gd-T cells",
                                          "B cells", "Plasmablasts",
                                          "Stellate cells", "Dividing cells", "Doublets"))

pltumap = ggplot(plot_df, aes(y = UMAPCSS_2, x = UMAPCSS_1, colour = allcells_simp))+
  geom_point(size = pointsize)+
  labs(colour = "Cell Type")+
  scale_colour_manual(values = colsallct)+
  guides(colour = guide_legend(override.aes = list(size = 2)))+
  theme(aspect.ratio = 1,
        legend.title = element_text(hjust = 0),
        axis.line = element_blank(),
        axis.text = element_blank())

pdf("figure_panels/fig2/umap_all_celltypes.pdf", height = 5, width = 6, useDingbats = F)
print(pltumap)
dev.off()
png("figure_panels/fig2/umap_all_celltypes.png", height = 325, width = 400, antialias = "subpixel")
print(pltumap)
dev.off()

Proportion of each cell type per condition

df_cnt = table(plot_df$allcells_simp, plot_df$Condition)[-c(15,16),]
df_cnt_hep = reshape2::melt(apply(df_cnt, 2, function(x) round(x/sum(x)*100, 1))[5,])
df_cnt_nohep = reshape2::melt(apply(df_cnt[-5,], 2, function(x) round(x/sum(x)*100, 1)))

df_cnt_all = rbind(data.frame("Var1" = "Hepatocytes", "Var2" = rownames(df_cnt_hep), 
                              "value" = df_cnt_hep$value),
                   df_cnt_nohep)

mat_cnt_all = reshape2::dcast(data = df_cnt_all, formula = Var1 ~ Var2, value.var = "value")
rownames(mat_cnt_all) = mat_cnt_all$Var1
mat_cnt_all = mat_cnt_all[,-1]
ctord = hclust(dist(mat_cnt_all[,c(2,1,3)]))$order
ctord = c(7, 4, 10, 9, 5, 14, 11, 8, 3, 12,1,6,2,13)

annot_df = unique(plot_df[,c("major_ct","allcells_simp")])
annot_df = data.frame(row.names = annot_df$allcells_simp, "ct" = annot_df$major_ct)
heatp = pheatmap::pheatmap(mat_cnt_all[ctord,c(2,1,3)], cluster_cols = F, cluster_rows = F, 
                           treeheight_row = F, display_numbers = T, gaps_row = c(1,1), 
                           number_color = c("black", "white")[as.integer(mat_cnt_all[ctord,c(2,1,3)]>50)+1],
                           color = colorRampPalette(brewer.pal(n = 9, name = "Blues"))(100),
                           fontsize_row = 8, fontsize_col = 8,
                           annotation_row = annot_df, annotation_colors = list(ct = colsmajor[-6]))

pdf("figure_panels/fig2/heatmap_all_celltypes_prop.pdf", height = 3.5, width = 5, useDingbats = F)
print(heatp)
dev.off()

UMAP with conditions

randomrows = sample(1:nrow(plot_df), size = nrow(plot_df), replace = F)
pltumapcond = ggplot(plot_df[randomrows,], aes(y = UMAPCSS_2, x = UMAPCSS_1, colour = Condition))+
  geom_point(size = pointsize)+
  labs(colour = "Condition")+
  scale_colour_manual(values = colcond)+
  guides(colour = guide_legend(override.aes = list(size = 2)))+
  theme(aspect.ratio = 1,
        legend.title = element_text(hjust = 0),
        axis.line = element_blank(),
        axis.text = element_blank())

pdf("figure_panels/fig2/umap_condition.pdf", height = 5, width = 6, useDingbats = F)
print(pltumapcond)
dev.off()
png("figure_panels/fig2/umap_condition.png", height = 325, width = 400, antialias = "subpixel")
print(pltumapcond)
dev.off()

Top GO terms and load data

# loading and preparing data
go_enr_list = readRDS(file = "results/cond_effect/go_enr_list.RDS")

go_enr_major = go_enr_list$major_ct
for(cc in names(go_enr_major)){ # adding the terms for subsampled hepatocytes
  for(ct in names(go_enr_major[[cc]])){
    if(ct=="Hepatocytes"){
      go_enr_major[[cc]][[ct]] = go_enr_list$major_ct_hep[[cc]]$Hepatocytes
    }
    go_enr_major[[cc]][[ct]] = go_enr_major[[cc]][[ct]][go_enr_major[[cc]][[ct]]$DB=="GO Term",]
  }
}


for(comp in names(go_enr_major)){
  for(ct in names(go_enr_major[[comp]])){
    subdir = "figure_panels/fig2/goterms_cond_full/"
    go_enr_major[[comp]][[ct]]$geneID = unlist(go_enr_major[[comp]][[ct]]$geneID)
    write.table(go_enr_major[[comp]][[ct]], 
                file = paste0(subdir, "GOTermBP_", comp, "_", ct, ".csv"), 
                col.names = T, row.names = F, quote = F, sep = ",")
  }
}

Plotting GO Terms mixed between conditions

terms_list = list()
for(ct in unique(names(go_enr_major$healthy_v_embolised))){
  emb_terms = go_enr_major$healthy_v_embolised[[ct]][,c(2,7,8,11)]
  emb_terms = emb_terms[emb_terms$cond!="healthy",]
  reg_terms = go_enr_major$healthy_v_regenerating[[ct]][,c(2,7,8,11)]
  reg_terms = reg_terms[reg_terms$cond!="healthy",]
  both_terms = merge(emb_terms, reg_terms, by = 1, all = T)[,-c(4,7)]
  colnames(both_terms)[2:5] = c("qval_embolized", "genes_embolized", 
                                "qval_regenerating", "genes_regenerating")
  both_terms$qval_embolized[is.na(both_terms$qval_embolized)] = 1
  both_terms$qval_regenerating[is.na(both_terms$qval_regenerating)] = 1
  both_terms$genes_embolized[is.na(both_terms$genes_embolized)] = ""
  both_terms$genes_regenerating[is.na(both_terms$genes_regenerating)] = ""
  
  both_terms$genes_all = unlist(lapply(strsplit(paste0(both_terms$genes_embolized, "/",
                                                       both_terms$genes_regenerating),"/"), 
                                       function(x) paste0(unique(x[x!=""]), collapse = "/")))
  
  both_terms = both_terms[both_terms$qval_embolized<=0.05 | both_terms$qval_regenerating<=0.05,]
  
  both_terms_top = getTopTermsPaired(both_terms, ncl = 12, nt = 1)
  terms_list[[ct]] = both_terms_top
}

plt_list = list()
for(ct in names(terms_list)){
  sum_df = terms_list[[ct]][,c(1:3,7)]
  sum_df$Description = breakStr(as.character(sum_df$Description), n = 30)
  sum_df$qval_max[sum_df$qval_embolized>sum_df$qval_regenerating] = 1-sum_df$qval_max[sum_df$qval_embolized>sum_df$qval_regenerating]
  plot_df = reshape2::melt(sum_df[,1:3])
  plot_df$Description = factor(plot_df$Description, levels = sum_df$Description[order(sum_df$qval_max)])
  plot_df$variable = unlist(lapply(strsplit(as.character(plot_df$variable), "_"), function(x) x[2]))
  
  plt_list[[ct]] = ggplot(plot_df, aes(x = -log10(value), y = Description, fill = variable))+
    geom_col(position = "dodge")+
    geom_vline(xintercept = -log10(0.05), linetype = "dashed")+
    scale_x_continuous(limits = c(0, max(-log10(plot_df$value)+0.3)), expand = c(0,0))+
    scale_fill_manual(values = colcond)+
    theme(legend.position = "none",
          axis.ticks = element_line())
}

for(n in names(plt_list)){
  pdf(paste0("figure_panels/fig2/goterms_cond/goterms_mixedGO_", n, ".pdf"), 
      height = 2.8, width = 3)
  print(plt_list[[n]])
  dev.off()
}

cowplot::plot_grid(plotlist = plt_list, ncol = 4, align = "hv")

Top enriched GO Terms - group similar terms and report the top 1 of each of 5 groups detected

goplt = list()
gotab = list()
for(comp in names(go_enr_major)){
  for(gr in names(go_enr_major[[comp]])){
    conds = strsplit(comp, "_v_")[[1]]
    for(cc in conds){
      sub_df = go_enr_major[[comp]][[gr]][go_enr_major[[comp]][[gr]]$DB=="GO Term" &
                                            go_enr_major[[comp]][[gr]]$qvalue<=0.05 &
                                            go_enr_major[[comp]][[gr]]$cond==cc,]
      if(nrow(sub_df)>0){
        sub_df = getTopTerms(sub_df, ncl = 5, nt = 1)
        sub_df = sub_df[order(sub_df$qvalue, decreasing = F),]
        l = ifelse(nrow(sub_df)>10, 10, nrow(sub_df))
        sub_df = sub_df[1:l,]
        sub_df$geneID = unlist(sub_df$geneID)
        sub_df$Description = breakStr(as.character(sub_df$Description), 30)
        sub_df$Description = factor(sub_df$Description, 
                                    levels = rev(as.character(sub_df$Description)))
        
        goplt[[paste0(comp, "__", gr, "__", cc)]] = ggplot(sub_df, 
                                                           aes(x = -log10(qvalue), y = Description))+
          geom_col()+
          scale_x_continuous(expand = c(0,0), limits = c(0, max(-log10(sub_df$qvalue))+0.25))+
          labs(y = "GO Term Description", title = paste0(cc, " vs ", conds[conds!=cc]))+
          theme(axis.ticks.x = element_line(),
                axis.text.y = element_text(hjust = 1, vjust = 0.5, lineheight = 0.75,
                                           size = 7),
                plot.title = element_text(size = 10, hjust = 0),
                plot.title.position = "plot")
        gotab[[paste0(comp, "__", gr, "__", cc)]] = sub_df
      }
    }
  }
}
for(n in names(goplt)){
  pdf(paste0("figure_panels/fig2/goterms_cond/goterms_filtGO_", n, ".pdf"), 
      height = 2, width = 3)
  print(goplt[[n]])
  dev.off()
  
  write.csv(gotab[[n]], file = paste0("figure_panels/fig2/goterms_cond/goterms_filtGO_", n, ".csv"),
            row.names = F, quote = F)
}

DE between conditions for cell types

filt_comps = readRDS(file = "results/cond_effect/all_filt_cond_comps.RDS")

for(comp in names(filt_comps$major_ct)){
  subdir = "figure_panels/fig2/DE_tables/"
  de_df = filt_comps$major_ct[[comp]]
  de_df = de_df[de_df$celltype!="Hepatocytes",]
  de_df = rbind(de_df, filt_comps$major_ct_hep[[comp]])
  de_df = de_df[de_df$p_val_adj<=0.05,]
  
  write.csv(de_df[order(de_df$avg_logFC, decreasing = T),], 
            file = paste0(subdir, "DEcond_major_ct_", comp, ".csv"), 
            col.names = T, row.names = F, quote = F)
}

for(g in names(filt_comps)){
  for(comp in names(filt_comps[[g]])){
    subdir = file.path("to_send", g)
    write.csv(filt_comps[[g]][[comp]], file = paste0(subdir, "/DEconditions_", comp, "_", g, ".csv"), 
              col.names = T, row.names = F, quote = F)
  }
}

Major cell types

genes_to_plot = list("Hepatocytes" = c("HAMP", "SAA1", "FGA", "G0S2", "TNFRSF1A",
                                       "CYP3A7", "MT1A", "DDX21", "IL1RAP", "MT1X",
                                       "MGLL", "MFSD2A", "APOA4", "IRF7", "CEBPA"), 
                      "Immune" = c("S100A9", "CD81", "FCGR1A", "GBP5", "RUNX3", 
                                   "CD300E", "MNDA", "IL18BP", "IL4I1", "WDFY4",
                                   "TRDC", "TRBC1", "IFNG", "CD160", "IFITM1"), 
                      "Cholangiocytes" = c("CCL2", "IRF1", "KRT19", "CCL20", "ICAM1",
                                           "MAP3K12", "EPSTI1", "P4HA1", "PEAK1", "SEC24A",
                                           "LCN2", "RAMP1", "ITGB4", "BIK", "CCL28"), 
                      "Mesenchymal" = c(), 
                      "Endothelial" = c("SOX18", "PLCG2", "TFPI2", "KLF2", "STC1",
                                        "CXXC5", "NPR3", "CDK6", "ADGRG6", "PDGFB",
                                        "RFPL1", "ITGB3", "ADAMTS4", "KLF13", "GPR182"))

plt_list_cond = list()
df_list_cond = list()
for(ct in unique(filt_comps$major_ct$healthy_v_embolised$celltype)){
  g = if(ct=="Hepatocytes") "major_ct_hep" else "major_ct" #use correct Hep DE
  
  # prepare data frame
  plt_reg = filt_comps[[g]]$healthy_v_regenerating[,c(1,3,4,5)]
  plt_reg = unique(plt_reg[plt_reg$celltype==ct,])
  plt_emb = filt_comps[[g]]$healthy_v_embolised[,c(1,3,4,5)]
  plt_emb = unique(plt_emb[plt_emb$celltype==ct,])
  rownames(plt_reg) = plt_reg$gene
  rownames(plt_emb) = plt_emb$gene
  
  # add FC/pval for genes that are not in common
  plt_df = merge(plt_emb, plt_reg, by = 0, all = T)
  rownames(plt_df) = plt_df[,1]
  plt_df = plt_df[,-c(1,3,6,7)]
  colnames(plt_df) = c("gene", "FC_emb", "pval_emb", "FC_reg", "pval_reg")
  plt_df$gene = rownames(plt_df)
  plt_df$FC_emb[is.na(plt_df$FC_emb)] = 0
  plt_df$FC_reg[is.na(plt_df$FC_reg)] = 0
  plt_df$pval_emb[is.na(plt_df$pval_emb)] = 1
  plt_df$pval_reg[is.na(plt_df$pval_reg)] = 1
  
  # condition labels
  plt_df$cond = ifelse(plt_df$FC_emb<=(-0.2) & plt_df$pval_emb<=0.05 & plt_df$FC_reg>=0, "embolised",
                       ifelse(plt_df$FC_reg<=(-0.2) & plt_df$pval_reg<=0.05 & plt_df$FC_emb>=0,
                              "regenerating",
                              ifelse(plt_df$FC_reg<=(-0.2) & plt_df$pval_reg<=0.05 & 
                                       plt_df$FC_emb<=(-0.2) & plt_df$pval_emb<=0.05, "both","other")))
  plt_df$cond = factor(plt_df$cond, levels = c("both", "embolised", "regenerating", "other"))
  plt_df = plt_df[order(plt_df$cond, decreasing = T),]
  
  # genes to plot
  b_g_plt = genes_to_plot[[ct]][1:5]
  emb_g_plt = genes_to_plot[[ct]][6:10]
  reg_g_plt = genes_to_plot[[ct]][11:15]
  
  cols = c("both" = "#C54635", "regenerating" = "salmon", "embolised" = "darkred", "other" = "grey85")
  plt = ggplot(plt_df, aes(x = FC_emb, y = FC_reg, colour = cond))+
    geom_vline(xintercept = 0)+
    geom_hline(yintercept = 0)+
    geom_point()+
    geom_label_repel(data = plt_df[plt_df$gene %in% c(emb_g_plt, reg_g_plt, b_g_plt),], 
                     mapping = aes(label = gene), show.legend = F, min.segment.length = 0, 
                     size = 2.75, label.padding = 0.15)+
    scale_colour_manual(values = cols)+
    labs(title = ct, x = "logFC(healthy vs embolised)", colour = "Condition",
         y = "logFC(healthy vs regenerating)")+
    theme_bw()+
    theme(axis.text = element_text(colour = "black"),
          aspect.ratio = 1)
  
  plt_list_cond[[ct]] = plt
}

pdf("figure_panels/fig2/DE_cond_major_celltypes.pdf", height = 5, width = 6, useDingbats = F)
print(plt_list_cond)
dev.off()
pdf("figure_panels/fig2/DE_cond_major_celltypes_noLeg.pdf", height = 5, width = 6, useDingbats = F)
plt_list_cond = lapply(plt_list_cond, function(x) x+theme(legend.position = "none"))
print(plt_list_cond)
dev.off()

All cell types

plt_list_cond = list()
df_list_cond = list()
for(ct in unique(filt_comps$cell_type$healthy_v_embolised$celltype)){
  g = if(ct=="Hepatocytes") "cell_type_hep" else "cell_type" #use correct Hep DE
  
  # prepare data frame
  plt_reg = filt_comps[[g]]$healthy_v_regenerating[,c(1,3,4,5)]
  plt_reg = unique(plt_reg[plt_reg$celltype==ct,])
  plt_emb = filt_comps[[g]]$healthy_v_embolised[,c(1,3,4,5)]
  plt_emb = unique(plt_emb[plt_emb$celltype==ct,])
  rownames(plt_reg) = plt_reg$gene
  rownames(plt_emb) = plt_emb$gene
  
  # add FC/pval for genes that are not in common
  plt_df = merge(plt_emb, plt_reg, by = 0, all = T)
  rownames(plt_df) = plt_df[,1]
  plt_df = plt_df[,-c(1,3,6,7)]
  colnames(plt_df) = c("gene", "FC_emb", "pval_emb", "FC_reg", "pval_reg")
  plt_df$gene = rownames(plt_df)
  plt_df$FC_emb[is.na(plt_df$FC_emb)] = 0
  plt_df$FC_reg[is.na(plt_df$FC_reg)] = 0
  plt_df$pval_emb[is.na(plt_df$pval_emb)] = 1
  plt_df$pval_reg[is.na(plt_df$pval_reg)] = 1
  
  # condition labels
  plt_df$cond = ifelse(plt_df$FC_emb<=(-0.2) & plt_df$pval_emb<=0.05 & plt_df$FC_reg>=0, "embolised",
                       ifelse(plt_df$FC_reg<=(-0.2) & plt_df$pval_reg<=0.05 & plt_df$FC_emb>=0,
                              "regenerating",
                              ifelse(plt_df$FC_reg<=(-0.2) & plt_df$pval_reg<=0.05 & 
                                       plt_df$FC_emb<=(-0.2) & plt_df$pval_emb<=0.05, "both","other")))
  plt_df$cond = factor(plt_df$cond, levels = c("both", "embolised", "regenerating", "other"))
  plt_df = plt_df[order(plt_df$cond, decreasing = T),]
  
  # genes to plot
  ord = order(plt_df$FC_emb+plt_df$FC_reg, decreasing = F)
  b_g_plt = plt_df$gene[ord][plt_df$cond[ord]=="both" & plt_df$pval_emb[ord]<=0.05 & plt_df$pval_reg[ord]<=0.05][1:5]
  ord = order(plt_df$FC_emb, decreasing = F)
  emb_g_plt = plt_df$gene[ord][plt_df$cond[ord]=="embolised" & plt_df$pval_emb[ord]<=0.05][1:5]
  ord = order(plt_df$FC_reg, decreasing = F)
  reg_g_plt = plt_df$gene[ord][plt_df$cond[ord]=="regenerating" & plt_df$pval_reg[ord]<=0.05][1:5]
  
  cols = c("both" = "#C54635", "regenerating" = "salmon", "embolised" = "darkred", "other" = "grey85")
  plt = ggplot(plt_df, aes(x = FC_emb, y = FC_reg, colour = cond))+
    geom_vline(xintercept = 0)+
    geom_hline(yintercept = 0)+
    geom_point()+
    geom_label_repel(data = plt_df[plt_df$gene %in% c(emb_g_plt, reg_g_plt, b_g_plt),], 
                     mapping = aes(label = gene), show.legend = F, min.segment.length = 0, 
                     size = 2.75, label.padding = 0.15)+
    scale_colour_manual(values = cols)+
    labs(title = ct, x = "logFC(healthy vs embolised)", colour = "Condition",
         y = "logFC(healthy vs regenerating)")+
    theme_bw()+
    theme(axis.text = element_text(colour = "black"),
          aspect.ratio = 1)
  
  plt_list_cond[[ct]] = plt
}

pdf("figure_panels/fig2/DE_cond_all_celltypes.pdf", height = 5, width = 6, useDingbats = F)
print(plt_list_cond)
dev.off()
pdf("figure_panels/fig2/DE_cond_all_celltypes_noLeg.pdf", height = 5, width = 6, useDingbats = F)
plt_list_cond = lapply(plt_list_cond, function(x) x+theme(legend.position = "none"))
print(plt_list_cond)
dev.off()

Count DE genes per cell type in conditions - major cell types

de_df = filt_comps$major_ct$healthy_v_embolised
de_df = de_df[de_df$p_val_adj<=0.05 & abs(de_df$avg_logFC)>=0.2,]
genes_up = tapply(de_df$gene[de_df$avg_logFC>0], de_df$celltype[de_df$avg_logFC>0], list)
genes_dn = tapply(de_df$gene[de_df$avg_logFC<0], de_df$celltype[de_df$avg_logFC<0], list)
de_hep = filt_comps$major_ct_hep$healthy_v_embolised
genes_up$Hepatocytes = de_hep$gene[de_hep$avg_logFC>=0.2 & de_hep$p_val_adj<=0.05]
genes_dn$Hepatocytes = de_hep$gene[de_hep$avg_logFC<=(-0.2) & de_hep$p_val_adj<=0.05]
de_df_g = rbind(reshape2::melt(genes_up), reshape2::melt(genes_dn))
de_df_g$dedir = c(rep("higher in healthy", length(unlist(genes_up))), 
                  rep("higher in embolised", length(unlist(genes_dn))))

de_df_r = filt_comps$major_ct$healthy_v_regenerating
de_df_r = de_df_r[de_df_r$p_val_adj<=0.05 & abs(de_df_r$avg_logFC)>=0.2,]
genes_up = tapply(de_df_r$gene[de_df_r$avg_logFC>0], de_df_r$celltype[de_df_r$avg_logFC>0], list)
genes_dn = tapply(de_df_r$gene[de_df_r$avg_logFC<0], de_df_r$celltype[de_df_r$avg_logFC<0], list)
de_hep = filt_comps$major_ct_hep$healthy_v_regenerating
genes_up$Hepatocytes = de_hep$gene[de_hep$avg_logFC>=0.2 & de_hep$p_val_adj<=0.05]
genes_dn$Hepatocytes = de_hep$gene[de_hep$avg_logFC<=(-0.2) & de_hep$p_val_adj<=0.05]
de_df_r_g = rbind(reshape2::melt(genes_up), reshape2::melt(genes_dn))
de_df_r_g$dedir = c(rep("higher in healthy", length(unlist(genes_up))), 
                    rep("higher in regenerating", length(unlist(genes_dn))))


counts_de = rbind(data.frame(table(de_df_g$L1, de_df_g$dedir)), data.frame(table(de_df_r_g$L1, de_df_r_g$dedir)))
counts_de$comp = rep(c("healthy vs embolised", "healthy vs regenerating"), each = 10)
counts_de$Var2 = factor(counts_de$Var2, 
                        levels = c("higher in healthy", "higher in embolised", "higher in regenerating"))

plt = ggplot(counts_de, aes(x = Var1, y = Freq, fill = Var2))+
  facet_wrap(~comp, nrow = 2)+
  scale_fill_manual(values = c("higher in healthy" = "orange", "higher in regenerating" = "salmon", 
                               "higher in embolised" = "darkred"))+
  scale_y_continuous(expand = c(0,0), limits = c(0, 4000))+
  labs(fill = "DE genes", x = "Cell types", y = "# DE genes")+
  geom_bar(stat = "identity")+
  theme_classic()+
  theme(legend.justification=c(0,1), legend.position=c(0,1),
        legend.box.background = element_rect(colour = "transparent", fill = "transparent"),
        legend.background = element_rect(colour = "transparent", fill = "transparent"),
        legend.key.size = unit(0.4, "cm"),
        axis.text = element_text(colour = "black"),
        axis.text.x = element_text(angle = 45, hjust = 1, vjust = 1))

pdf("figure_panels/fig2/barplot_decond_major.pdf", height = 5, width = 3, useDingbats = F)
print(plt)
dev.off()
png("figure_panels/fig2/barplot_decond_major.png", height = 500, width = 350, antialias = "subpixel")
print(plt)
dev.off()

Count DE genes per cell type in conditions - all cell types

de_df = filt_comps$cell_type_simp$healthy_v_embolised
de_df = de_df[de_df$p_val_adj<=0.05 & abs(de_df$avg_logFC)>=0.2,]
genes_up = tapply(de_df$gene[de_df$avg_logFC>0], de_df$celltype[de_df$avg_logFC>0], list)
genes_dn = tapply(de_df$gene[de_df$avg_logFC<0], de_df$celltype[de_df$avg_logFC<0], list)
de_hep = filt_comps$major_ct_hep$healthy_v_embolised
genes_up$Hepatocytes = de_hep$gene[de_hep$avg_logFC>=0.2 & de_hep$p_val_adj<=0.05]
genes_dn$Hepatocytes = de_hep$gene[de_hep$avg_logFC<=(-0.2) & de_hep$p_val_adj<=0.05]
de_df_g = rbind(reshape2::melt(genes_up), reshape2::melt(genes_dn))
de_df_g$dedir = c(rep("higher in healthy", length(unlist(genes_up))), 
                  rep("higher in embolised", length(unlist(genes_dn))))

de_df_r = filt_comps$cell_type_simp$healthy_v_regenerating
de_df_r = de_df_r[de_df_r$p_val_adj<=0.05 & abs(de_df_r$avg_logFC)>=0.2,]
genes_up = tapply(de_df_r$gene[de_df_r$avg_logFC>0], de_df_r$celltype[de_df_r$avg_logFC>0], list)
genes_dn = tapply(de_df_r$gene[de_df_r$avg_logFC<0], de_df_r$celltype[de_df_r$avg_logFC<0], list)
de_hep = filt_comps$major_ct_hep$healthy_v_regenerating
genes_up$Hepatocytes = de_hep$gene[de_hep$avg_logFC>=0.2 & de_hep$p_val_adj<=0.05]
genes_dn$Hepatocytes = de_hep$gene[de_hep$avg_logFC<=(-0.2) & de_hep$p_val_adj<=0.05]
de_df_r_g = rbind(reshape2::melt(genes_up), reshape2::melt(genes_dn))
de_df_r_g$dedir = c(rep("higher in healthy", length(unlist(genes_up))), 
                    rep("higher in regenerating", length(unlist(genes_dn))))

counts_de = rbind(data.frame(table(de_df_g$L1, de_df_g$dedir)), 
                  data.frame(table(de_df_r_g$L1, de_df_r_g$dedir)))
counts_de$comp = rep(c("healthy vs embolised", "healthy vs regenerating"), each = 14)
counts_de$Var2 = factor(counts_de$Var2, 
                        levels = c("higher in healthy", "higher in embolised", "higher in regenerating"))

plt = ggplot(counts_de, aes(x = Var1, y = Freq, fill = Var2))+
  facet_wrap(~comp)+
  scale_fill_manual(values = c("higher in healthy" = "orange", 
                               "higher in regenerating" = "salmon", "higher in embolised" = "darkred"))+
  scale_y_continuous(expand = c(0,0), limits = c(0, 3500))+
  labs(fill = "DE genes", x = "Cell types", y = "# DE genes")+
  geom_bar(stat = "identity")+
  theme_classic()+
  theme(legend.justification=c(0,1), legend.position=c(0,1),
        legend.box.background = element_rect(colour = "transparent", fill = "transparent"),
        legend.background = element_rect(colour = "transparent", fill = "transparent"),
        legend.key.size = unit(0.4, "cm"),
        axis.text = element_text(colour = "black"),
        axis.text.x = element_text(angle = 45, hjust = 1, vjust = 1))

pdf("figure_panels/fig2/barplot_decond_all.pdf", height = 4, width = 6, useDingbats = F)
print(plt)
dev.off()
png("figure_panels/fig2/barplot_decond_all.png", height = 350, width = 500, antialias = "subpixel")
print(plt)
dev.off()

Supplementary

Gene and UMI counts per major cell type and condition

plot_df = allcells_css@meta.data
plot_df$Condition = factor(plot_df$Condition, levels = c("healthy", "embolised", "regenerating"))
plot_df$major_ct = factor(plot_df$major_ct, levels = c("Hepatocytes", "Endothelial", "Cholangiocytes", "Immune", "Mesenchymal"))

vio_counts_ct = ggplot(plot_df[!is.na(plot_df$major_ct),], 
                       aes(y = nCount_SCT, x = Condition, fill = Condition))+
  facet_wrap(~major_ct, scales = "free_x")+
  geom_violin()+
  scale_y_log10(name = "# UMI (normalised)")+
  scale_fill_manual(values = colcond)+
  theme(panel.grid.major.y = element_line(colour = "grey85"),
        legend.position = "none",
        axis.text = element_text(),
        axis.text.x = element_text(size = 9),
        axis.title.x = element_text(size = 10),
        strip.text = element_text(size = 9),
        strip.background = element_rect(fill = "transparent", colour = "black", size = 0.9))

pdf("figure_panels/fig2/violin_ncounts_major_celltype.pdf", height = 4, width = 7, useDingbats = F)
print(vio_counts_ct)
dev.off()
png("figure_panels/fig2/violin_ncounts_major_celltype.png", height = 425, width = 550, antialias = "subpixel")
print(vio_counts_ct)
dev.off()

vio_counts_ct = ggplot(plot_df[!is.na(plot_df$major_ct),], 
                       aes(y = nFeature_SCT, x = Condition, fill = Condition))+
  facet_wrap(~major_ct, scales = "free_x")+
  geom_violin()+
  scale_y_log10(name = "# Genes")+
  scale_fill_manual(values = colcond)+
  theme(panel.grid.major.y = element_line(colour = "grey85"),
        legend.position = "none",
        axis.text = element_text(),
        axis.text.x = element_text(size = 9),
        axis.title.x = element_text(size = 10),
        strip.text = element_text(size = 9),
        strip.background = element_rect(fill = "transparent", colour = "black", size = 0.9))

pdf("figure_panels/fig2/violin_ngenes_major_celltype.pdf", height = 4, width = 7, useDingbats = F)
print(vio_counts_ct)
dev.off()
png("figure_panels/fig2/violin_ngenes_major_celltype.png", height = 425, width = 550, antialias = "subpixel")
print(vio_counts_ct)
dev.off()

nUMI in filtered and kept cells

c_meta = Reduce(rbind, lapply(cond_srat, function(x) x@meta.data))[,c(11,12,13,14,15,17,23)]
h_meta = Reduce(rbind, lapply(healthy_srat, function(x) x@meta.data))[,c(11,12,13,14,15,17,23)]
all_meta = rbind(h_meta, c_meta)

all_meta$keep_allfilt = factor(c("No", "Yes")[all_meta$keep_allfilt+1], levels = c("Yes", "No"))
all_meta$Name = factor(all_meta$Name, 
                       levels = paste0("sc_", c(paste0("H",1:3),paste0("E",c(1:3,5:7)),paste0("R",c(1:3,5:7)))))
levels(all_meta$Name) = paste0("sc_", c(paste0("H",1:3),paste0("E",1:6),paste0("R",1:6)))

n_cells = all_meta %>% count(Name, Fraction, keep_allfilt)

plt = ggplot(all_meta, aes(x = Fraction, y = nCount_SCT, fill = keep_allfilt, colour = keep_allfilt))+
  facet_wrap(~Name, scales = "free", nrow = 3)+
  geom_violin(scale = "width")+
  scale_colour_manual(values = c("Yes" = "grey20","No" = "grey80"))+
  scale_fill_manual(values = c("Yes" = "grey20","No" = "grey80"))+
  scale_y_log10()+
  labs(y = "nUMI", colour = "keep", fill = "keep")+
  theme(strip.background = element_rect(fill = "transparent", colour = "black", size = 1),
        strip.text = element_text(margin = margin(2,0,2,0), size = 9),
        axis.ticks = element_line(), 
        axis.text.y = element_text(size = 6.5))

pdf("figure_panels/fig2/filtering_nUMI.pdf", height = 3.3, width = 7.1, useDingbats = F)
print(plt)
dev.off()

UMAP with healthy donors split

plot_df = data.frame(allcells_css@reductions$umap_css@cell.embeddings)
plot_df$Donor = factor(allcells_css@meta.data$Name)
plot_df$Donor = plyr::revalue(plot_df$Donor, c("sc_E5" = "sc_E4", "sc_R5" = "sc_R4", 
                                               "sc_E6" = "sc_E5", "sc_R6" = "sc_R5",
                                               "sc_E7" = "sc_E6", "sc_R7" = "sc_R6"))
plot_df$Donor = factor(plot_df$Donor, levels = c("sc_H1", "sc_H2", "sc_H3", "sc_E1", "sc_R1", "sc_E2", 
                                                 "sc_R2", "sc_E3", "sc_R3", "sc_E4", "sc_R4", "sc_E5", 
                                                 "sc_R5", "sc_E6", "sc_R6"))
plot_df$Condition = factor(allcells_css@meta.data$Condition, 
                           levels = c("healthy", "embolised", "regenerating"))
plot_df$major_ct = allcells_css@meta.data$major_ct
plot_df$allcells_major = allcells_css@meta.data$allcells_major
plot_df$major_ct[is.na(plot_df$major_ct)] = plot_df$allcells_major[is.na(plot_df$major_ct)]
plot_df$major_ct[plot_df$major_ct=="Dividing cells"] = "Immune" # the detected dividing cells are mostly (if not all) immune 
plot_df$major_ct = factor(plot_df$major_ct, levels = c("Hepatocytes", "Endothelial","Immune",
                                                       "Cholangiocytes","Mesenchymal", "Doublets"))

plt = ggplot(plot_df[sample(1:nrow(plot_df), nrow(plot_df), replace = F),], 
             aes(x = UMAPCSS_1, y = UMAPCSS_2, colour = major_ct))+
  facet_wrap(~Donor, drop = T, nrow = 3, ncol = 5)+
  geom_point(size = 0.08)+
  guides(colour = guide_legend(override.aes = list(size = 3), title = "Donors"))+
  scale_colour_manual(values = colsmajor)+
  theme_classic()+
  th_gen+
  theme(axis.line = element_blank(),
        axis.ticks = element_blank(),
        axis.title = element_blank(),
        axis.text = element_blank(),
        strip.text.x = element_text(size = 8, margin = margin(0.06,0,0.06,0, "cm")),
        strip.background.x = element_rect(size = 0.5, colour = "transparent"),
        legend.title = element_text(hjust = 0),
        aspect.ratio = 1)

pdf("figure_panels/fig2/umapAll_fresh_donors_split.pdf", 
    useDingbats = F, height = 4.1, width = 6.4)
print(plt)
dev.off()
png("figure_panels/fig2/umapAll_fresh_donors_split.png", 
    height=8, width=15, unit="cm", res=600, antialias = "subpixel")
print(plt)
dev.off()
pdf("figure_panels/fig2/umapAll_fresh_donors_noLeg_split.pdf", 
    useDingbats = F, height = 4.1, width = 5.8)
print(plt+theme(legend.position = "none"))
dev.off()
png("figure_panels/fig2/umapAll_fresh_donors_noLeg_split.png", 
    height=8, width=11, unit="cm", res=600, antialias = "subpixel")
print(plt+theme(legend.position = "none"))
dev.off()
pdf("figure_panels/fig2/umapAll_fresh_donors_split_cond.pdf", 
    useDingbats = F, height = 4.1, width = 6.4)
print(plt+facet_wrap(Condition~Donor, drop = T, nrow = 3, ncol = 5))
dev.off()
png("figure_panels/fig2/umapAll_fresh_donors_split_cond.png", 
    height=8, width=15, unit="cm", res=600, antialias = "subpixel")
print(plt+facet_wrap(Condition~Donor, drop = T, nrow = 3, ncol = 5))
dev.off()

Figure 3

Main Figure

Zonation between conditions

# gene expression
hep_cells = readRDS(file = "results/zonation_cond/hep_cells_zonation_rank.RDS")

# fitted expression
hep_sig_fits = readRDS(file = "results/zonation_cond/hep_sig_fits.RDS")
hep_fits_qval = readRDS(file = "results/zonation_cond/hep_fits_qval.RDS")

# GO and clusters
hep_res_list = readRDS(file = "results/zonation_cond/hep_got_clustering_list.RDS")

g_list = c( # embolised clusters
  "COX7C", # oxygen transport chain (also in regen 2)
  "CYP39A1", # steroid metabolism
  "ARG1", # organic acid catabolic process (also in regen 2)
  "PROX1", # developing liver marker
  "COPA", # vesicle trafficking (also in regen 1)
  "CDH2", # cluster 4
  "CD151", # cluster 4
           # regenerating clusters
  "AGPAT2", # lipid metabolism
  "COX6C", # electron transport chain
  "PTGR1", # fatty acid metabolism
  "FOXA3", # liver development (cluster 1)
  "FOXO1", # control of metabolism and CC arrest
  "CYP2A6", # cluster 4
  "CYP2B6", # cluster 4
  "CYP4A11", # cluster 4
  "SDC4", # cluster 4
  "STAT1", # cluster 4
  # normal zonation
  "SAA1", "SAA2", "HAMP", "C3", "CYP2E1","CYP1A2","HULC","BCHE","CYP3A4",
  "CRP", "SDS", "HAL", "IGFBP1", "IGFBP2", "BAAT", "SLCO1B3")
hep_df = data.frame(vals = c(hep_cells$healthy$zonation_pt, hep_cells$embolised$zonation_pt,
                              hep_cells$regenerating$zonation_pt), 
                     Condition = c(rep("healthy", length(hep_cells$healthy$zonation_pt)), 
                                   rep("embolised", length(hep_cells$embolised$zonation_pt)), 
                                   rep("regenerating", length(hep_cells$regenerating$zonation_pt))),
                     Donor = c(hep_cells$healthy$Donor, 
                               hep_cells$embolised$Donor, hep_cells$regenerating$Donor),
                     ct = c(hep_cells$healthy$allcells_simp, 
                               hep_cells$embolised$allcells_simp, hep_cells$regenerating$allcells_simp))
hep_df$bins10 = cut(hep_df$vals, 10)
hep_df$Condition = factor(hep_df$Condition, levels = c("healthy", "embolised", "regenerating"))
levels(hep_df$Donor) = c("sc_E1/R1", "sc_E2/R2", "sc_E3/R3", "sc_E4/R4", "sc_E5/R5", "sc_E6/R6", 
                         "sc_H1", "sc_H2", "sc_H3")

plt_dists = ggplot(hep_df, aes(x = bins10, fill = Condition))+
     facet_wrap(~Condition)+
     geom_bar()+
     labs(x = "zonation (binned)", y = "Number of cells")+
     scale_y_continuous(expand = c(0,0))+
     scale_fill_manual(values = colcond)+
     coord_flip()+
     guides(fill = guide_legend(title.position = "left"))+
     theme(axis.text.y = element_blank(),
           legend.title.align = 0,
           legend.position = "bottom",
           legend.box.margin = margin(0,0,0,0),
           legend.box.spacing = unit(0.05, "cm"))

pdf("figure_panels/fig3/hep_zonation_conditionDist.pdf", height = 2.3, width = 3.6, useDingbats = F)
print(plt_dists)
dev.off()

Donor density per condition

hep_don = ggplot(hep_df, aes(x = vals, colour = Donor))+
     facet_wrap(~Condition, scales = "free_y")+
     geom_hline(yintercept = 0)+
     geom_density()+
     labs(x = "zonation", y = "cell density")+
     scale_y_continuous(expand = c(0,0))+
     coord_flip()+
     guides(colour = guide_legend(title.position = "left", nrow = 3))+
     theme(axis.text.y = element_blank(),
           axis.ticks.x = element_line(),
           strip.text = element_text(margin = margin(0.04,0,0.04,0, "cm"), size = 7.5),
           legend.title.align = 0,
           legend.position = "bottom",
           legend.box.margin = margin(0,0,0,0),
           legend.box.spacing = unit(0.05, "cm"))

pdf("figure_panels/fig3/hep_zonation_conditionDonors.pdf", height = 3, width = 3.6, useDingbats = F)
print(hep_don)
dev.off()

Zonation grouped by donors

hep_don = ggplot(hep_df, aes(x = vals, colour = Condition))+
     facet_wrap(~Donor, scales = "free_y")+
     geom_hline(yintercept = 0)+
     geom_density()+
     labs(x = "zonation", y = "cell density")+
     scale_colour_manual(values = colcond)+
     scale_y_continuous(expand = c(0,0))+
     coord_flip()+
     guides(colour = guide_legend(title.position = "left", ncol = 3))+
     theme(axis.text.y = element_blank(),
           axis.ticks.x = element_line(),
           strip.text = element_text(margin = margin(0.04,0,0.04,0, "cm"), size = 7.5),
           legend.title.align = 0,
           legend.position = "bottom",
           legend.box.margin = margin(0,0,0,0),
           legend.box.spacing = unit(0.05, "cm"))

pdf("figure_panels/fig3/hep_zonation_DonorsCond.pdf", height = 3, width = 3.6, useDingbats = F)
print(hep_don)
dev.off()

Hep binned zonation normalised to healthy

hep_df = data.frame(vals = c(hep_cells$healthy$zonation_pt, hep_cells$embolised$zonation_pt,
                              hep_cells$regenerating$zonation_pt), 
                     Condition = c(rep("healthy", length(hep_cells$healthy$zonation_pt)), 
                                   rep("embolised", length(hep_cells$embolised$zonation_pt)), 
                                   rep("regenerating", length(hep_cells$regenerating$zonation_pt))))
hep_df$bins10 = cut(hep_df$vals, 10)
hep_df$Condition = factor(hep_df$Condition, levels = c("healthy", "embolised", "regenerating"))
hep_df = data.frame(table(hep_df$Condition, hep_df$bins10))
hep_df = hep_df[order(hep_df$Var1),]
hep_df$Freqnorm = unlist(tapply(hep_df$Freq, hep_df$Var1, function(x) x/sum(x)))
hep_df$Freqnorm_h = hep_df$Freqnorm/mean(hep_df$Freqnorm[hep_df$Var1=="healthy"])

plt_dists = ggplot(hep_df, aes(x = Var2, fill = Var1, y = Freqnorm_h))+
     facet_wrap(~Var1)+
     geom_col()+
     labs(x = "zonation (binned)", y = "Proportion of cells (compared to healthy)")+
     scale_y_continuous(expand = c(0,0), labels = c("0", "0.5", "1", "1.5", "2", "2.5"))+
     scale_fill_manual(values = colcond)+
     coord_flip()+
     guides(fill = guide_legend(title.position = "left"))+
     theme(axis.text.y = element_blank(),
           axis.text.x = element_text(size = 6),
           legend.position = "none")

pdf("figure_panels/fig3/hep_zonation_conditionDist_norm.pdf", 
    height = 2, width = 3.8, useDingbats = F)
print(plt_dists)
dev.off()

Plot GO Terms (general)

go_theme = theme_bw()+
  theme(axis.text = element_text(colour = "black", size = 7.5),
        axis.title = element_text(size = 8),
        plot.title = element_text(size = 9),
        plot.title.position = "plot",
        plot.subtitle = element_text(size = 7.5),
        axis.text.y = element_text(vjust = 0.6, colour = c("grey45", "grey17")),
        panel.grid.major.y = element_blank())

gopltFunc = function(plot_df, tit = "", subtit = ""){
  plot_df$Description = breakStr(plot_df$Description, 30)
  plot_df$Description = factor(plot_df$Description, levels = rev(plot_df$Description))
  plot_df$fill = as.character(rep(1:2, ceiling(nrow(plot_df)/2)))[1:nrow(plot_df)]
  plt = ggplot(plot_df, aes(x = -log10(qvalue), y = Description, fill = fill))+
    geom_col(show.legend = F)+
    scale_x_continuous(expand = c(0,0), lim = c(0, max(-log10(plot_df$qvalue))+1))+
    scale_fill_manual(values = c("grey17", "grey45"))+
    labs(title = tit, subtitle = subtit)+
    go_theme
  return(plt)
}

pdf("figure_panels/fig3/hep_go_emb_notcorr.pdf", height = 3.2, width = 3.6, useDingbats = F)
print(gopltFunc(hep_res_list$embolised$go_cl$all, tit = "GO Terms - Embolised", subtit = "cor < 0.3"))
dev.off()

pdf("figure_panels/fig3/hep_go_emb_corr.pdf", height = 3.2, width = 3.6, useDingbats = F)
print(gopltFunc(hep_res_list$embolised$go_cl$pos, tit = "GO Terms - Embolised", subtit = "cor < 0.3"))
dev.off()

pdf("figure_panels/fig3/hep_go_reg_notcorr.pdf", height = 3.2, width = 3.6, useDingbats = F)
print(gopltFunc(hep_res_list$regenerating$go_cl$all, tit = "GO Terms - Regenerating", subtit = "cor >= 0.3"))
dev.off()

pdf("figure_panels/fig3/hep_go_reg_corr.pdf", height = 3.2, width = 3.6, useDingbats = F)
print(gopltFunc(hep_res_list$regenerating$go_cl$pos, tit = "GO Terms - Regenerating", subtit = "cor >= 0.3"))
dev.off()

Plot GO Terms (each cluster)

pathgo = "figure_panels/fig3/goterms_clusters/"
dir.create(pathgo, showWarnings = FALSE)

for(cc in names(hep_res_list)){
  tit = ifelse(cc=="embolised", "GO Terms - Embolised", "GO Terms - Regenerating")
  for(n in 1:5){
    plot_df = hep_res_list[[cc]]$go_cl[[as.character(n)]]
    if(nrow(plot_df)>0){
      plt = gopltFunc(plot_df, tit = tit, subtit = paste0("Cluster ", n, "; cor < 0.3"))
      if(nrow(plot_df)%%2==1){
        plt = plt + theme(axis.text.y = element_text(vjust = 0.6, colour = c("grey17","grey45")))
      }
      pdf(paste0(pathgo, "hep_go_", cc, "_cl", n, ".pdf"), height = 3.2, width = 3.6, useDingbats = F)
      print(plt)
      dev.off()
    }
  }
}

Plots for individual genes

geneplot_theme = theme_bw()+
    theme(aspect.ratio = 1/1.5,
          panel.grid = element_blank(),
          axis.text = element_text(colour = "black", size = 7),
          axis.title = element_text(size = 8),
          plot.title = element_text(size = 10, face = "italic"),
          plot.title.position = "plot",
          legend.position = "bottom",
          legend.box.margin = margin(0,0,0,0),
          legend.box.spacing = unit(0.01,"cm"),
          legend.text = element_text(size = 8),
          legend.title = element_text(size = 9))

plt_gene_list = list()
for(g in g_list){
  plt_df = data.frame("exp" = c(hep_sig_fits$healthy[,g], hep_sig_fits$embolised[,g]),
                    "cond" = rep(c("healthy", "embolised"), each = 100),
                    "t" = rep(1:100, 2))
  plt_df$cond = factor(plt_df$cond, levels = c("healthy", "embolised"))
  pltemb = ggplot(plt_df, aes(x = t, y = exp, group = cond, col = cond))+
    geom_line(size = 1.5)+
    labs(x = "zonation", y = "Expression", title = g)+
    scale_colour_manual(values = colcond)+
    geneplot_theme
  
  plt_df = data.frame("exp" = c(hep_sig_fits$healthy[,g], hep_sig_fits$regenerating[,g]),
                    "cond" = rep(c("healthy", "regenerating"), each = 100),
                    "t" = rep(1:100, 2))
  plt_df$cond = factor(plt_df$cond, levels = c("healthy", "regenerating"))
  pltreg = ggplot(plt_df, aes(x = t, y = exp, group = cond, col = cond))+
    geom_line(size = 1.5)+
    labs(x = "zonation", y = "Expression", title = g)+
    scale_colour_manual(values = colcond)+
    geneplot_theme
  print(cowplot::plot_grid(pltemb, pltreg, ncol = 2))
  
  plt_gene_list[[g]] = list("embolised" = pltemb, "regenerating" = pltreg)
}
for(g in names(plt_gene_list)){
  for(n in names(plt_gene_list[[g]])){
    pdf(paste0("figure_panels/fig3/hep_zon_", g, "_",  n, ".pdf"), 
        height = 2.2, width = 2.5, useDingbats = F)
    print(plt_gene_list[[g]][[n]])
    dev.off()
  }
}

Plot individual genes with all three conditions

plt_3_list = list()
for(g in g_list){
  plt_df = data.frame("exp" = c(hep_sig_fits$healthy[,g], hep_sig_fits$embolised[,g],
                                hep_sig_fits$regenerating[,g]),
                    "cond" = rep(c("healthy", "embolised", "regenerating"), each = 100),
                    "t" = rep(1:100, 3))
  plt_df$cond = factor(plt_df$cond, levels = c("healthy", "embolised", "regenerating"))
  plt_3_list[[g]] = ggplot(plt_df, aes(x = t, y = exp, group = cond, col = cond))+
    geom_line(size = 1.5)+
    labs(x = "zonation", y = "Expression", title = g, colour = "Condition")+
    scale_colour_manual(values = colcond)+
    guides(colour = guide_legend(title.position = "top"))+
    geneplot_theme
}

for(g in names(plt_3_list)){
  pdf(paste0("figure_panels/fig3/hep_zon_", g, "_all.pdf"), 
      height = 2.5, width = 3, useDingbats = F)
  print(plt_3_list[[g]])
  dev.off()
}

Plot mean profiles

for(n in names(hep_res_list)){
  plot_df2 = hep_res_list[[n]]$df
  xxx = plot_df2[plot_df2$cond=="difference",]
  labsdf = data.frame(labs = c("higher in\nhealthy", paste0("higher in\n", n)), coord = c(0.5, -0.5))
  plt1 = ggplot(xxx, aes(x = Var1, y = value))+
      facet_grid(~cls, scales = "free")+
      geom_hline(yintercept = 0, colour = "grey60", size = 0.75, linetype = "dashed")+
      stat_summary(fun.data=mean_cl_boot, colour="grey40", alpha = 0.35, geom="linerange", group=1)+
      stat_summary(fun=mean, colour="black", geom="line", group=1)+
      labs(x = "zonation", y = "difference in\nscaled expression")+
      scale_y_continuous(limits = c(-1,1))+
      theme_bw()+
      theme(axis.text = element_text(colour = "black", size = 7),
            axis.title = element_text(size = 8))
  plt2 = ggplot()+
    geom_text(data = labsdf, mapping = aes(y = coord, label = labs), 
              x = 0.5, angle = 270, size = 3)+
    scale_x_continuous(limits = c(0,1))+
    scale_y_continuous(limits = c(-1,1))+
    cowplot::theme_nothing()
  plt = cowplot::plot_grid(plt1, plt2, ncol = 2, nrow = 1, rel_widths = c(1, 0.085), align = "hv")
  
  pdf(paste0("figure_panels/fig3/hep_zon_", n, "_mean.pdf"), height = 1.8, width = 6, useDingbats = F)
  print(plt)
  dev.off()
}

Plot heatmaps

# get profiles for plotting
usegenes = unique(c(as.character(hep_res_list$embolised$df$Var2),
                    as.character(hep_res_list$regenerating$df$Var2)))

bins_list = list()
for(n in names(hep_cells)){
  plot_df = cbind(data.frame("pt" = rep(1:10, each = 10)),hep_sig_fits[[n]][,usegenes])
  plot_df$bins10 = cut(plot_df$pt, 10)
  bins_list[[n]] = sapply(usegenes, function(x) scale(tapply(plot_df[,x], 
                                                             plot_df$bins10, mean))[10:1])
}
bins_mean = Reduce(rbind, bins_list)
colnames(bins_mean) = usegenes

# choose genes for plotting
ecl_genes = merge(unique(hep_res_list$embolised$df[,c(1,4)]), hep_fits_qval$embolised$fdr, 
                  by.x = 1,  by.y = 0)
top_e = ecl_genes %>% group_by(cls) %>% slice_min(order_by = pval_list, n = 5)
emb_heat = pheatmap(bins_mean[1:20,as.character(top_e$Var2)], show_rownames = F, 
                    fontsize_col = 6.2, border_color = NA, gaps_row = c(10,20), gaps_col = seq(5, 20, 5), 
                    clustering_method = "ward.D2", cluster_rows = F, cluster_cols = F, fontsize = 6)
pdf("figure_panels/fig3/heatmap_zonation_emb.pdf", height=2.5, width=3.8, useDingbats = F)
print(emb_heat)
dev.off()
write.csv(ecl_genes, file = "figure_panels/fig3/hep_embolised_clusters_fdr.csv", row.names = F, quote = F)

rcl_genes = merge(unique(hep_res_list$regenerating$df[,c(1,4)]), hep_fits_qval$regenerating$fdr, 
                  by.x = 1,  by.y = 0)
top_r = rcl_genes %>% group_by(cls) %>% slice_min(order_by = pval_list, n = 5)
reg_heat = pheatmap(bins_mean[c(1:10, 21:30),as.character(top_r$Var2)], show_rownames = F, 
                    fontsize_col = 7.5, border_color = NA, gaps_row = c(10,20), gaps_col = seq(5, 20, 5), 
                    clustering_method = "ward.D2", cluster_rows = F, cluster_cols = F, fontsize = 6.7)
pdf("figure_panels/fig3/heatmap_zonation_reg.pdf", height=2.5, width=3.8, useDingbats = F)
print(reg_heat)
dev.off()
write.csv(rcl_genes, file = "figure_panels/fig3/hep_regen_clusters_fdr.csv", row.names = F, quote = F)

Figure 4

Main Figure

Load data

only_end_cells = readRDS(file = "results/endothelial/only_end_cells_zon.RDS")
all_cor_end = read.csv("results/endothelial/correlations_zonation_endothelial.csv", 
                       header = T, row.names = 1)
end_fits_qval = readRDS(file = "results/endothelial/end_fits_qval.RDS")
mksimp = read.csv("results/endothelial/markers_endo_subpop_simp.csv", header = T, row.names = 1)
mksimp = mksimp[order(mksimp$avg_logFC, decreasing = T),]

top_genes = readRDS(file = "results/cond_effect/top_genes_mk.RDS")

go_end = readRDS("results/endothelial/GOTerms_correlations.RDS")

UMAPs

endo_col = c("Periportal LSEC" = "aquamarine2",  "Midzonal LSEC" = "aquamarine3",
             "Pericentral LSEC" = "aquamarine4", "LSEC (fenestr.)" = "darkslategray1",
             "LSEC (remodelling)" = "cyan4", "LSEC (interferon)" = "darkslateblue",
             "LSEC (high MT 1)" = "blueviolet", "LSEC (high MT 2)" = "darkviolet",
             "LSEC (stress)" = "lightblue", "EC non-LSEC" = "forestgreen", 
             "Lymphatic EC" = "chartreuse3", "Cycling cells" = "grey20")

plot_df = cbind(only_end_cells@meta.data[,c("endo_simp", "Condition", "Donor")],
                only_end_cells@reductions$umap@cell.embeddings)
plot_df$Condition = factor(plot_df$Condition, levels = c("healthy", "embolised", "regenerating"))
plot_df$endo_simp = factor(plot_df$endo_simp, levels = names(endo_col))
plot_df$Donor = plyr::revalue(plot_df$Donor, c("HD1" = "sc_H1", "HD2" = "sc_H2", "HD3" = "sc_H3", 
                                               "DD1" = "sc_E1/sc_R1", "DD2" = "sc_E2/sc_R2", 
                                               "DD3" = "sc_E3/sc_R3", "DD5" = "sc_E4/sc_R4", 
                                               "DD6" = "sc_E5/sc_R5", "DD7" = "sc_E6/sc_R6"))
plot_df$Donor = factor(plot_df$Donor, levels = c("sc_H1", "sc_H2", "sc_H3", "sc_E1/sc_R1",
                                                 "sc_E2/sc_R2", "sc_E3/sc_R3", "sc_E4/sc_R4", 
                                                 "sc_E5/sc_R5", "sc_E6/sc_R6"))
set.seed(1)
plot_df = plot_df[sample(1:nrow(plot_df), size = nrow(plot_df), replace = F),]

plt_subtypes = ggplot(plot_df, aes(x = UMAP_1, y = UMAP_2, colour = endo_simp))+
  geom_point(size = 0.1)+
  guides(colour = guide_legend(override.aes = list(size = 1.75)))+
  scale_colour_manual(values = endo_col)+
  theme(aspect.ratio = 1,
        legend.title = element_blank(),
        legend.text = element_text(size = 8),
        legend.box.spacing = unit(0.01, "cm"),
        axis.line = element_blank(),
        axis.text = element_blank(),
        axis.title = element_blank())

plt_cond = ggplot(plot_df, aes(x = UMAP_1, y = UMAP_2, colour = Condition))+
  geom_point(size = 0.1)+
  guides(colour = guide_legend(override.aes = list(size = 1.75)))+
  scale_colour_manual(values = colcond)+
  theme(aspect.ratio = 1,
        legend.title = element_blank(),
        legend.text = element_text(size = 8),
        legend.box.spacing = unit(0.01, "cm"),
        axis.line = element_blank(),
        axis.text = element_blank(),
        axis.title = element_blank())

plt_don = ggplot(plot_df, aes(x = UMAP_1, y = UMAP_2, colour = Donor))+
  geom_point(size = 0.1)+
  guides(colour = guide_legend(override.aes = list(size = 1.75)))+
  scale_colour_manual(values = coldonall)+
  theme(aspect.ratio = 1,
        legend.title = element_blank(),
        legend.text = element_text(size = 8),
        legend.box.spacing = unit(0.01, "cm"),
        axis.line = element_blank(),
        axis.text = element_blank(),
        axis.title = element_blank())

pdf("figure_panels/fig_endo/umap_clusters.pdf", height=2.2, width=3.6, useDingbats = F)
print(plt_subtypes)
dev.off()
pdf("figure_panels/fig_endo/umap_cond.pdf", height=2.2, width=3.6, useDingbats = F)
print(plt_cond)
dev.off()
pdf("figure_panels/fig_endo/umap_donors.pdf", height=2.2, width=3.6, useDingbats = F)
print(plt_don)
dev.off()

png("figure_panels/fig_endo/umap_clusters.png", height=6.25, width=6.25, unit="cm", 
    res=600, antialias = "subpixel")
print(plt_subtypes+theme(legend.position = "none"))
dev.off()
png("figure_panels/fig_endo/umap_cond.png", height=6.25, width=6.25, unit="cm", 
    res=600, antialias = "subpixel")
print(plt_cond+theme(legend.position = "none"))
dev.off()
png("figure_panels/fig_endo/umap_donors.png", height=6.25, width=6.25, unit="cm", 
    res=600, antialias = "subpixel")
print(plt_don+theme(legend.position = "none"))
dev.off()

Frequency tables

df_cnt = table(only_end_cells$endo_simp, only_end_cells$Condition)
df_cnt_perCond = reshape2::melt(apply(df_cnt, 2, function(x) round(x/sum(x)*100, 1)))
df_cnt_perCl = reshape2::melt(apply(df_cnt, 1, function(x) round(x/sum(x)*100, 1)))

mat_cnt_all = reshape2::dcast(data = df_cnt_perCl, formula = Var1 ~ Var2, value.var = "value")
rownames(mat_cnt_all) = mat_cnt_all$Var1
mat_cnt_all = t(mat_cnt_all[,-1])
ctord = hclust(dist(mat_cnt_all[,c(2,1,3)]))$order

heatp = pheatmap::pheatmap(mat_cnt_all[ctord,c(2,1,3)], cluster_cols = F, cluster_rows = F, 
                           treeheight_row = F, display_numbers = T, fontsize_number = 7, 
                           number_color = c("black", "white")[as.integer(mat_cnt_all[ctord,c(2,1,3)]>50)+1],
                           color = colorRampPalette(brewer.pal(n = 9, name = "Blues"))(100),
                           fontsize_row = 7.5, fontsize_col = 7.5, angle_col = 0)

pdf("figure_panels/fig_endo/cluster_proportion_cond.pdf", height=3.2, width=3.3, useDingbats = F)
print(heatp)
dev.off()

Markers

mkplot = c("MGP", "AQP1", "CLEC14A", "EDNRB", "CLEC1B", "CLEC4G", "PLVAP", "RBP7", "ANGPT2", "CTGF",
           "ISG15", "IFIT3", "MRO", "EGR1","PTGDS", "INMT", "PROX1", "CCL21", "TOP2A")

expdf = reshape2::melt(cbind(data.frame(t(only_end_cells@assays$SCT@data[mkplot,]),
                                        "endo_simp" = only_end_cells$endo_simp)))
expdf$endo_simp = factor(expdf$endo_simp, levels = names(endo_col))

vioplt = ggplot(expdf, aes(x = endo_simp, y = value, fill = endo_simp))+
  facet_grid(variable~., scales = "free_y")+
  geom_violin(scale = "width", colour = "grey82")+
  scale_fill_manual(values = endo_col)+
  scale_y_continuous(breaks = c(0, 2, 4))+
  labs(y = "Expression")+
  theme(legend.position = "none",
        axis.text.x = element_text(angle = -30, hjust = 0, vjust = 0.9),
        axis.title.x = element_blank(),
        axis.text.y = element_text(size = 6.5),
        axis.ticks = element_line(),
        strip.text.y = element_text(angle = 0, size = 7, margin = margin(0,0,0,0)),
        strip.background = element_rect(colour = "white", fill = "white"))

pdf("figure_panels/fig_endo/violins_mk.pdf", height=5.8, width=3.4, useDingbats = F)
print(vioplt)
dev.off()

boxplt = ggplot(expdf, aes(x = endo_simp, y = value, fill = endo_simp))+
  facet_grid(variable~., scales = "free_y")+
  geom_boxplot(colour = "grey50", outlier.shape = NA, size = 0.25)+
  scale_fill_manual(values = endo_col)+
  scale_y_continuous(breaks = c(0, 2, 4))+
  labs(y = "Expression")+
  theme(legend.position = "none",
        axis.text.x = element_text(angle = -30, hjust = 0, vjust = 0.9),
        axis.title.x = element_blank(),
        axis.text.y = element_text(size = 6.5),
        axis.ticks = element_line(),
        strip.text.y = element_text(angle = 0, size = 7, margin = margin(0,0,0,0)),
        strip.background = element_rect(colour = "white", fill = "white"))

pdf("figure_panels/fig_endo/boxes_mk.pdf", height=5.8, width=3.4, useDingbats = F)
print(boxplt)
dev.off()

Binned zonation

plot_df = only_end_cells@meta.data[only_end_cells@meta.data$endo_simp %in% c("Periportal LSEC", "Midzonal LSEC", "Pericentral LSEC") & only_end_cells@meta.data$goodcl,]
plot_df$bins100 = cut(plot_df$zonation_pt, 10)
plot_df$Condition = factor(plot_df$Condition, levels = c("healthy", "embolised", "regenerating"))
end_df = data.frame(table(plot_df$Condition, plot_df$bins10))
end_df = end_df[order(end_df$Var1),]
end_df$Freqnorm = unlist(tapply(end_df$Freq, end_df$Var1, function(x) x/sum(x)))
end_df$Freqnorm_h = end_df$Freqnorm/mean(end_df$Freqnorm[end_df$Var1=="healthy"])

plt_dists = ggplot(end_df, aes(x = Var2, fill = Var1, y = Freqnorm_h))+
     facet_wrap(~Var1)+
     geom_col()+
     labs(x = "zonation (binned)", y = "Proportion of cells (compared to healthy)")+
     scale_y_continuous(expand = c(0,0), labels = c("0", "0.5", "1", "1.5", "2"))+
     scale_fill_manual(values = colcond)+
     coord_flip()+
     guides(fill = guide_legend(title.position = "left"))+
     theme(axis.text.y = element_blank(),
           axis.text.x = element_text(size = 6),
           legend.position = "none")

pdf("figure_panels/fig_endo/endo_zonation_conditionDist_norm.pdf", 
    height = 2, width = 3.8, useDingbats = F)
print(plt_dists)
dev.off()

Donor distributions

end_df = only_end_cells@meta.data[only_end_cells$goodcl,]

end_df = data.frame(vals = end_df$zonation_pt, 
                    Condition = end_df$Condition,
                    Donor = end_df$Donor,
                    ct = end_df$endo_simp)
end_df$bins10 = cut(end_df$vals, 10)
end_df$Condition = factor(end_df$Condition, levels = c("healthy", "regenerating", "embolised"))
end_df$Donor = factor(end_df$Donor)
end_df$Donor = plyr::revalue(end_df$Donor, c("HD1" = "sc_H1", "HD2" = "sc_H2", "HD3" = "sc_H3", 
                                             "DD1" = "sc_R1/E1", "DD2" = "sc_R2/E2", "DD3" = "sc_R3/E3",
                                             "DD5" = "sc_R4/E4", "DD6" = "sc_R5/E5", "DD7" = "sc_R6/E6"))
end_df$Donor = factor(end_df$Donor, levels = levels(end_df$Donor)[c(7:9, 1:6)])

end_don = ggplot(end_df, aes(x = vals, colour = Condition))+
  facet_wrap(~Donor, scales = "free_y")+
  geom_hline(yintercept = 0)+
  geom_density(size = 1.05)+
  labs(x = "Zonation", y = "Cell density")+
  scale_colour_manual(values = colcond)+
  scale_y_continuous(expand = c(0,0))+
  coord_flip()+
  guides(colour = guide_legend(title.position = "left", ncol = 3))+
  theme(axis.text.y = element_blank(),
        axis.ticks.x = element_line(),
        strip.text = element_text(margin = margin(0.04,0,0.04,0, "cm"), size = 7.5),
        strip.background = element_rect(fill = "white", colour = "white"),
        legend.title.align = 0,
        aspect.ratio = 0.8,
        legend.position = "bottom",
        legend.box.margin = margin(0,0,0,0),
        legend.box.spacing = unit(0.05, "cm"))

pdf("figure_panels/fig_endo/end_zonation_DonorsCond.pdf", height = 3.8, width = 3.4, useDingbats = F)
print(end_don)
dev.off()

Predicted zonation for other populations

plot_df = only_end_cells@meta.data[only_end_cells@meta.data$endo_simp %in% names(endo_col)[1:9],]
plot_df$bins100 = cut(plot_df$zonation_pt, 10)
plot_df$Condition = factor(plot_df$Condition, levels = c("healthy", "embolised", "regenerating"))
plot_df$endo_simp = factor(plot_df$endo_simp, levels = names(endo_col))

plot_ptall = ggplot(plot_df, aes(y = zonation_pt, x = endo_simp, fill = Condition))+
  facet_wrap(~endo_simp, scales = "free_x", ncol = 3)+
  geom_violin()+
  labs(y = "zonation", x = "clusters")+
  scale_y_continuous(expand = c(0,0), breaks = c(0, 0.25, 0.5, 0.75, 1), limits = c(0,1))+
  scale_fill_manual(values = colcond)+
  guides(fill = guide_legend(title.position = "left"))+
  theme_bw()+
  theme(axis.text.x = element_blank(),
        axis.ticks.x = element_blank(),
        axis.text.y = element_text(colour = "black", size = 7),
        axis.title = element_text(size = 8),
        strip.background = element_rect(fill = "white", colour = "black"),
        strip.text = element_text(size = 8),
        legend.title = element_blank(),
        legend.key.size = unit(0.3, "cm"),
        legend.box.spacing = unit(0.01, "cm"),
        legend.position = "bottom")

pdf("figure_panels/fig_endo/zonation_allLSEC.pdf", height=3.5, width=3.85, useDingbats = F)
print(plot_ptall)
dev.off()

Heatmap

only_end_cells_split = SplitObject(only_end_cells[,only_end_cells$goodcl], split.by = "Condition")

# filter markers from other cell types (can contaminate)
mk_others = unique(unlist(top_genes$cell_type[!grepl("LSEC ", names(top_genes$cell_type))]))
cor_sub = all_cor_end[!(all_cor_end$gene %in% mk_others),]

topgenes = unique(c(cor_sub$gene[order(cor_sub$HvE, decreasing = T)][1:30],
                    cor_sub$gene[order(cor_sub$HvR, decreasing = T)][1:30]))
bottomgenes = unique(c(cor_sub$gene[order(cor_sub$HvE, decreasing = F)][1:35],
                    cor_sub$gene[order(cor_sub$HvR, decreasing = F)][1:35]))

usegenes = c(topgenes, bottomgenes)

bins_list = list()
for(n in names(only_end_cells_split)){
  plot_df = cbind(data.frame("pt" = rep(1:10, each = 10)),end_fits_qval[[n]]$fits[,usegenes])
  plot_df$bins10 = cut(plot_df$pt, 10)
  bins_list[[n]] = sapply(usegenes, function(x) scale(tapply(plot_df[,x], 
                                                             plot_df$bins10, mean))[10:1])
}
bins_mean = Reduce(rbind, bins_list)

hct = hclust(dist(t(bins_list$healthy[,topgenes])), method = "ward.D2")
hcb = hclust(dist(t(bins_mean[,bottomgenes])), method = "ward.D2")
ord = c(topgenes[hct$order], bottomgenes[hcb$order])
cutb = factor(cutree(hcb, 10)[hcb$order], levels = unique(cutree(hcb, 8)[hcb$order]))

gaps = cumsum(table(cutb))[-10]+length(topgenes)

heat_plt = pheatmap(bins_mean[,ord], show_rownames = F, fontsize_col = 6.2, border_color = NA,
                    gaps_row = c(10,20), gaps_col = c(length(topgenes), gaps),
                    clustering_method = "ward.D2", cluster_rows = F, cluster_cols = F)

pdf("figure_panels/fig_endo/heatmap_corZon.pdf", height=3, width=7.8, useDingbats = F)
print(heat_plt)
dev.off()

GO Terms

go_theme = theme_bw()+
  theme(axis.text = element_text(colour = "black", size = 7.5),
        axis.title = element_text(size = 8),
        plot.title = element_text(size = 9),
        plot.title.position = "plot",
        plot.subtitle = element_text(size = 7.5),
        axis.text.y = element_text(vjust = 0.6, colour = c("grey45", "grey17")),
        panel.grid.major.y = element_blank())

gopltFunc = function(plot_df, tit = "", subtit = ""){
  plot_df$Description = breakStr(plot_df$Description, 30)
  plot_df$Description = factor(plot_df$Description, levels = rev(plot_df$Description))
  plot_df$fill = as.character(rep(1:2, ceiling(nrow(plot_df)/2)))[1:nrow(plot_df)]
  plt = ggplot(plot_df, aes(x = -log10(qvalue), y = Description, fill = fill))+
    geom_col(show.legend = F)+
    scale_x_continuous(expand = c(0,0), lim = c(0, max(-log10(plot_df$qvalue))+1))+
    scale_fill_manual(values = c("grey17", "grey45"))+
    labs(title = tit, subtitle = subtit)+
    go_theme
  return(plt)
}

pdf("figure_panels/fig_endo/end_go_emb_corr.pdf", height = 3.2, width = 3.6, useDingbats = F)
print(gopltFunc(go_end$cor_he, tit = "GO Terms - Embolised", subtit = "cor >= 0.3"))
dev.off()

pdf("figure_panels/fig_endo/end_go_reg_corr.pdf", height = 3.2, width = 3.6, useDingbats = F)
print(gopltFunc(go_end$cor_hr, tit = "GO Terms - Regenerating", subtit = "cor >= 0.3"))
dev.off()

Figure 5

Main Figure

Total interactions per cell type in each condition

net_names_l = readRDS(file = "results/cell_comm/updt/count_net_list.RDS")
# list per condition with interactions, genes, mean
reform_list = readRDS(file = "results/cell_comm/updt/reform_list.RDS")
# list per cond with ligand or receptor expression for each interaction
scoring_mats = readRDS(file = "results/cell_comm/updt/scoring_mats.RDS")
# reform_list + DE info + uniqueness/specificity of interaction/ligand/receptor
inter_df = readRDS(file = "results/cell_comm/updt/cond_diff_interact_DE.RDS")
# interactions qith certain functions involving which cell types and in which conditions
ct_g_cond_ann = readRDS(file = "results/cell_comm/updt/ct_g_cond_ann.RDS")
# interaction with L and R, pair of cell types, mean exp, and function
ct_int_exp_l = readRDS(file = "results/cell_comm/updt/interact_celltype_exp_group_list.RDS")
# annotation for all interactions
inter_annot = read.csv("data/interaction_annotation.csv", header = T)
inter_annot$funct[grepl("imm", inter_annot$funct)] = "immune"
inter_annot$funct[grepl("inflam", inter_annot$funct)] = "immune"
# mut info data
her_allint = readRDS(file = "./results/cell_comm/updt/interactions_mutInfo_condComp.RDS")
# GSEA on mutual info results
all_gsea_list = readRDS(file = "./results/cell_comm/updt/allgsea_interactions_mutInfo_condComp.RDS")
simp_gsea_list = readRDS(file = "./results/cell_comm/updt/simpgsea_interactions_mutInfo_condComp.RDS")
# network data
load("results/cell_comm/updt/median_networks_cond.RData")
load("results/cell_comm/updt/networks_cond.RData")
load("results/cell_comm/updt/median_networks_cond_midct.RData")
load("results/cell_comm/updt/median_networks_cond_umap.RData")
load("results/cell_comm/updt/networks_cond_umap.RData")
load("results/cell_comm/updt/median_networks_cond_umap_midct.RData")
comph_inters = readRDS(file = "results/cell_comm/updt/comph_inters.RDS")

Plot changes in number of interactions per condition

net_names_l = readRDS(file = "results/cell_comm/updt/count_net_list.RDS")

# list per condition with interactions, genes, mean
reform_list = readRDS(file = "results/cell_comm/updt/reform_list.RDS")
# list per cond with ligand or receptor expression for each interaction
scoring_mats = readRDS(file = "results/cell_comm/updt/scoring_mats.RDS")
# reform_list + DE info + uniqueness/specificity of interaction/ligand/receptor
inter_df = readRDS(file = "results/cell_comm/updt/cond_diff_interact_DE.RDS")
# interactions qith certain functions involving which cell types and in which conditions
ct_g_cond_ann = readRDS(file = "results/cell_comm/updt/ct_g_cond_ann.RDS")
# interaction with L and R, pair of cell types, mean exp, and function
ct_int_exp_l = readRDS(file = "results/cell_comm/updt/interact_celltype_exp_group_list.RDS")
# annotation for all interactions
inter_annot = read.csv("data/interaction_annotation.csv", header = T)
inter_annot$funct[grepl("imm", inter_annot$funct)] = "immune"
inter_annot$funct[grepl("inflam", inter_annot$funct)] = "immune"
# mut info data
her_allint = readRDS(file = "./results/cell_comm/updt/interactions_mutInfo_condComp.RDS")
# GSEA on mutual info results
all_gsea_list = readRDS(file = "./results/cell_comm/updt/allgsea_interactions_mutInfo_condComp.RDS")
simp_gsea_list = readRDS(file = "./results/cell_comm/updt/simpgsea_interactions_mutInfo_condComp.RDS")
# network data
load("results/cell_comm/updt/median_networks_cond.RData")
load("results/cell_comm/updt/networks_cond.RData")
load("results/cell_comm/updt/median_networks_cond_midct.RData")
load("results/cell_comm/updt/median_networks_cond_umap.RData")
load("results/cell_comm/updt/networks_cond_umap.RData")
load("results/cell_comm/updt/median_networks_cond_umap_midct.RData")
comph_inters = readRDS(file = "results/cell_comm/updt/comph_inters.RDS")

Non-ubiquitous interaction functions per cell type and condition

# correct some names
reform_list_int = list()
for(n in names(reform_list)[1:3]){
  reform_list[[n]]$ct1[grepl("Hepa", reform_list[[n]]$ct1)] = "Hepatocytes"
  reform_list[[n]]$ct2[grepl("Hepa", reform_list[[n]]$ct2)] = "Hepatocytes"
  reform_list[[n]]$ct1[grepl("LSEC_", reform_list[[n]]$ct1)] = "LSEC"
  reform_list[[n]]$ct2[grepl("LSEC_", reform_list[[n]]$ct2)] = "LSEC"
  reform_list_int[[n]] = reform_list[[n]][reform_list[[n]]$ct1!="Dividing cells" &
                                            reform_list[[n]]$ct2!="Dividing cells",]
  reform_list_int[[n]] = reform_list_int[[n]][!duplicated(reform_list_int[[n]][,1:3]),1:3]
}

# count interactions
infer_df = data.frame(expand.grid(unique(reform_list_int$healthy$ct1), 
                                  unique(reform_list_int$healthy$ct1)))
nr = nrow(infer_df)
infer_df = rbind(infer_df, infer_df, infer_df)
infer_df$count = 0
infer_df$cond = rep(names(reform_list)[1:3], each = nr)
colnames(infer_df)[1:2] = c("SOURCE", "TARGET")
for(i in 1:nrow(infer_df)){
  tmp = reform_list_int[[infer_df[i,4]]]
  infer_df[i,3] = dim(tmp[(tmp$ct1==infer_df[i,1] & tmp$ct2==infer_df[i,2]) |
                            (tmp$ct2==infer_df[i,1] & tmp$ct1==infer_df[i,2]),])[1]
}
## make one to count over all
infer_all = data.frame(expand.grid(unique(reform_list_int$healthy$ct1), 
                                   unique(reform_list_int$healthy$ct1)))
infer_all$count = 0
colnames(infer_all)[1:2] = c("SOURCE", "TARGET")
reform_all_int = unique(Reduce(rbind, reform_list_int))
for(i in 1:nrow(infer_all)){
  infer_all[i,3] = infer_all[i,3]+dim(tmp[(reform_all_int$ct1==infer_all[i,1] & reform_all_int$ct2==infer_all[i,2]) |
                                            (reform_all_int$ct2==infer_all[i,1] & reform_all_int$ct1==infer_all[i,2]),])[1]
}

infer_df_list = list(healthy = infer_df[infer_df$cond=="healthy",],
                     embolised = infer_df[infer_df$cond=="embolised",],
                     regenerating = infer_df[infer_df$cond=="regenerating",],
                     all = infer_all)

net_names_all = t(Reduce(rbind, lapply(infer_df_list[1:3], function(x) tapply(x$count, x$SOURCE, sum))))
colnames(net_names_all) = names(net_names_l)[1:3]
net_names_all = reshape2::melt(net_names_all)
net_names_all$Var1 = factor(net_names_all$Var1, 
                            levels = net_names_all[net_names_all$Var2=="healthy","Var1"][order(net_names_all[net_names_all$Var2=="healthy","value"], decreasing = F)])

total_unique = data.frame(t(t(Reduce(rbind, lapply(infer_df_list[4], 
                                                   function(x) tapply(x$count, x$SOURCE, sum))))))
total_unique$Var1 = rownames(total_unique)
colnames(total_unique)[1] = "value"
total_unique$Var2 = "total unique"

net_names_all$Var1 = factor(net_names_all$Var1, 
                            levels = total_unique$Var1[order(total_unique$value, 
                                                             decreasing = F)])
plt_counts = ggplot(net_names_all, aes(x = Var1, y = value))+
  geom_point(mapping = aes(colour = Var2), size = 1.6)+
  geom_point(data = total_unique, mapping = aes(shape = Var2), size = 1.6)+
  coord_flip()+
  scale_colour_manual(values = colcond)+
  scale_shape_manual(values = c(4))+
  scale_y_continuous(expand = c(0,0), limits = c(0,6500))+
  labs(y = "Total interactions", x = "Cell Type", colour = "Condition")+
  guides(colour = guide_legend(order = 1), shape = guide_legend(order = 2, title = NULL))+
  theme_bw()+
  theme(axis.text.x = element_text(angle = 30, vjust = 1, hjust = 1),
        axis.text = element_text(colour = "black"),
        axis.title.x = element_text(size = 8),
        legend.margin = margin(1, 1, 1, 1),
        legend.spacing.x = unit(0.05, "cm"),
        legend.direction = "horizontal",legend.box = "horizontal")
leg = cowplot::get_legend(plt_counts)

perc_df = data.frame("Var1" = net_names_all$Var1,
                     "Var2" = net_names_all$Var2,
                     "perc" = c(rep(0, length(unique(net_names_all$Var1))),
                                (net_names_all$value[net_names_all$Var2=="embolised"]-net_names_all$value[net_names_all$Var2=="healthy"])/net_names_all$value[net_names_all$Var2=="healthy"],
                                (net_names_all$value[net_names_all$Var2=="regenerating"]-net_names_all$value[net_names_all$Var2=="healthy"])/net_names_all$value[net_names_all$Var2=="healthy"])*100)
perc_df$col = ifelse(perc_df$perc>0, "green", "red")
perc_df = perc_df[perc_df$Var2!="healthy",]

perc_plt_emb = ggplot(perc_df[perc_df$Var2=="embolised",], aes(x = Var1, y = perc, fill = col))+
  geom_col()+
  scale_fill_manual(values = c("deepskyblue1", "red1"))+
  scale_y_continuous(expand = c(0,0), limits = c(-45,70))+
  coord_flip()+
  labs(y = "% change\nembolised vs healthy", x = "Cell Type")+
  theme_bw()+
  theme(axis.text.x = element_text(angle = 30, vjust = 1, hjust = 1, colour = "black"),
        axis.text.y = element_blank(),
        axis.title.x = element_text(size = 8),
        axis.title.y = element_blank(),
        axis.ticks.y = element_blank(),
        legend.position = "none")
perc_plt_reg = ggplot(perc_df[perc_df$Var2=="regenerating",], aes(x = Var1, y = perc, fill = col))+
  geom_col()+
  scale_fill_manual(values = c("deepskyblue1", "red1"))+
  scale_y_continuous(expand = c(0,0), limits = c(-45,70))+
  coord_flip()+
  labs(y = "% change\nregenerating vs healthy", x = "Cell Type")+
  theme_bw()+
  theme(axis.text.x = element_text(angle = 30, vjust = 1, hjust = 1, colour = "black"),
        axis.text.y = element_blank(),
        axis.title.x = element_text(size = 8),
        axis.title.y = element_blank(),
        axis.ticks.y = element_blank(),
        legend.position = "none")

cowplot::plot_grid(cowplot::plot_grid(plt_counts+theme(legend.position = "none"), 
                                      perc_plt_emb, perc_plt_reg, 
                                      ncol = 3, align = "h", axis = "r", rel_widths = c(1,0.5,0.5)),
                   leg, nrow = 2, rel_heights = c(1, 0.1))

pdf("figure_panels_rev1/fig_comm/mainFig_countsCond.pdf", height = 7, width = 7)
cowplot::plot_grid(cowplot::plot_grid(plt_counts+theme(legend.position = "none"), 
                                      perc_plt_reg, perc_plt_emb, 
                                      ncol = 3, align = "h", axis = "r", rel_widths = c(1,0.4,0.4)),
                   leg, nrow = 2, rel_heights = c(1, 0.1))
dev.off()
png 
  2 

Interaction functions per cell type and condition (using all interactions)

# interactions have to be absent in at least one condition
plot_df = ct_g_cond_ann[ct_g_cond_ann$celltypes %in% c("Stellate cells", "LSEC", "Kupffer cells", "cDCs",
                                                       "pDCs", "Endothelial cells (non-LSEC)") & 
                          ct_g_cond_ann$description %in% c("ECM", "inflammation", "migration",
                                                           "development", "immune activity", 
                                                           "immune suppression", "immune regulation"),]
plot_df$description = gsub(" ", "\n", plot_df$description, fixed = T)
plot_df$celltypes = gsub(" (", "\n(", plot_df$celltypes, fixed = T)
plot_df$description[grepl("immune", plot_df$description) | 
                      grepl("inflamm", plot_df$description)] = "immune"
bar_func_sub = ggplot(plot_df, aes(x = condition, fill = condition))+
  facet_grid(celltypes~description, scales = "free_y")+
  geom_bar()+
  scale_fill_manual(values = colcond)+
  theme_classic()+
  theme(axis.text.x = element_text(angle = 45, hjust = 1, vjust = 1, size = 7, colour = "black"),
        axis.text.y = element_text(size = 6.3, colour = "black"),
        axis.title = element_text(size = 7),
        axis.line = element_blank(),
        panel.background = element_rect(colour = "black"),
        panel.grid.major.y = element_line(),
        strip.text = element_text(size = 7),
        strip.background = element_blank(),
        aspect.ratio = 1,
        legend.position = "none")

pdf("figure_panels_rev1/fig_comm/mainFig_funcPart.pdf", height = 5.5, width = 4.5)
print(bar_func_sub)
dev.off()
null device 
          1 
plot_df = ct_g_cond_ann
plot_df$description = gsub(" ", "\n", plot_df$description, fixed = T)
plot_df$celltypes = gsub(" (", "\n(", plot_df$celltypes, fixed = T)
plot_df$description[grepl("immune", plot_df$description) | 
                      grepl("inflamm", plot_df$description)] = "immune"
bar_func_all = ggplot(plot_df, aes(x = condition, fill = condition))+
  facet_grid(celltypes~description, scales = "free_y")+
  geom_bar()+
  scale_fill_manual(values = colcond)+
  theme_classic()+
  theme(axis.text.x = element_text(angle = 45, hjust = 1, vjust = 1, size = 7, colour = "black"),
        axis.text.y = element_text(size = 6.3, colour = "black"),
        axis.title = element_text(size = 7),
        axis.line = element_blank(),
        panel.background = element_rect(colour = "black"),
        panel.grid.major.y = element_line(),
        strip.text = element_text(size = 7),
        strip.background = element_blank(),
        aspect.ratio = 1/2,
        legend.position = "none")

pdf("figure_panels_rev1/fig_comm/suppFig_countsFunc.pdf", paper = "a4", width = 9, height = 13.5)
print(bar_func_all)
*** recursive gc invocation
*** recursive gc invocation
*** recursive gc invocation
*** recursive gc invocation
*** recursive gc invocation
*** recursive gc invocation
*** recursive gc invocation
*** recursive gc invocation
dev.off()
null device 
          1 

GSEA qvalue for changing interactions (using all)

plot_df = Reduce(rbind, reform_list[1:3])
plot_df$cond = c(rep("healthy", nrow(reform_list$healthy)), 
                 rep("embolised", nrow(reform_list$embolised)), 
                 rep("regenerating", nrow(reform_list$regenerating)))
plot_df = unique(plot_df)
plot_df = data.frame(rbind(as.matrix(plot_df[,c(1,2,8)]), as.matrix(plot_df[,c(1,3,8)])))
plot_df = merge(plot_df, inter_annot, by = 1, all.x = T)
colnames(plot_df) = c("interaction", "celltypes", "condition", "description")

plot_df$description = gsub(" ", "\n", plot_df$description, fixed = T)
plot_df$celltypes = gsub(" (", "\n(", plot_df$celltypes, fixed = T)
plot_df$description[grepl("immune", plot_df$description) | 
                      grepl("inflamm", plot_df$description)] = "immune"
bar_func_all = ggplot(plot_df, aes(x = condition, fill = condition))+
  facet_grid(description~celltypes, scales = "free_y")+
  geom_bar()+
  scale_fill_manual(values = colcond)+
  theme_classic()+
  theme(axis.text.x = element_text(angle = 45, hjust = 1, vjust = 1, size = 7, colour = "black"),
        axis.text.y = element_text(size = 6.3, colour = "black"),
        axis.title = element_text(size = 7),
        axis.line = element_blank(),
        panel.background = element_rect(colour = "black"),
        panel.grid.major.y = element_line(),
        strip.text = element_text(size = 7),
        strip.background = element_blank(),
        aspect.ratio = 1,
        legend.position = "none")

Interaction expression matrices

plot_df = Reduce(rbind, all_gsea_list)
plot_df$q.val = -log10(plot_df$q.val+0.0000005)*(plot_df$sscore/abs(plot_df$sscore))
plot_df$comp = factor(plot_df$comp, levels = rev(c("he","hr","er")))
m = tapply(plot_df$q.val, plot_df$group,mean)
plot_df$group = factor(plot_df$group, levels = names(m)[order(m, decreasing = F)])
plot_df = plot_df[plot_df$comp!="er",]
plot_df$comp = as.character(plyr::revalue(plot_df$comp, 
                                          c("hr" = "regenerating", "he" = "embolised", "er" = "nothing")))
plot_df$comp = factor(plot_df$comp, levels = c("regenerating", "embolised"))

gseaplt = ggplot(plot_df, aes(x = q.val, y = group, fill = comp))+
  geom_col(position = "dodge")+
  geom_vline(xintercept = c(log10(0.05), -log10(0.05)), linetype = "dashed")+
  geom_vline(xintercept = c(0))+
  scale_fill_manual(values = colcond, drop = T)+
  guides(fill = guide_legend(title = "healthy vs", reverse = T))+
  labs(x = "q-value x score signal", y = "interaction type", fill = "comparison")+
  theme_bw()+
  theme(axis.text = element_text(colour = "black", size = 7),
        axis.title = element_text(colour = "black", size = 7.5),
        legend.position = c(0,1),
        legend.justification = c(-0.05,1.05),
        legend.title = element_text(size = 7.5),
        legend.text = element_text(size = 7),
        legend.margin = margin(0,0,0,0),
        legend.key.size = unit(0.35, "cm"))

pdf("figure_panels_rev1/fig_comm/mainFig_funcGSEA.pdf", height = 2.2, width = 2.85)
print(gseaplt)
dev.off()
null device 
          1 

Network plots - MDS

pltboth = ggplot()+
  geom_point(data = point_cond_df, mapping = aes(x = X1, y = X2, colour = ct2), 
             alpha = 0.6, show.legend = NA, size = 1.3)+
  geom_segment(data = pe_l[[2]], 
               mapping = aes(x = X1.x, xend = X1.y, y = X2.x, yend = X2.y, size = Freq), 
               alpha = 0.15, show.legend = F)+
  geom_point(data = pe_l[[1]], 
             mapping = aes(x = X1, y = X2, fill = ct), 
             alpha = 1, pch = 21, size = 4)+
  guides(colour = guide_legend(override.aes = list(size = 2.3)))+
  scale_size_continuous(range = c(0, 4), limits = range(pe_l[[2]]$Freq))+
  scale_colour_manual(values = colsmajor)+
  #scale_fill_manual(values = colsallct)+
  theme_classic()+ 
  theme(aspect.ratio = 1, 
        axis.line = element_blank(),
        axis.text = element_blank(),
        axis.title = element_blank(),
        axis.ticks = element_blank(),
        legend.title = element_blank(),
        legend.key.size = unit(0.35, "cm"),
        legend.spacing.y = unit(0.1, "cm"),
        legend.position = "none")
pdf("figure_panels_rev1/fig_comm/mainFig_inet_cond_all.pdf", 
    height = 3.1, width = 5.2, useDingbats = F)
print(pltboth)
dev.off()

plt_cond_l_ch = list()
for(cc in unique(pe_cond_l_ch[[2]]$condition)){
  plt_cond_l_ch[[cc]] = ggplot()+
    geom_segment(data = pe_cond_l_ch[[2]][pe_cond_l_ch[[2]]$condition==cc,], 
                 mapping = aes(x = X1.x, xend = X1.y, y = X2.x, yend = X2.y, size = Freq, alpha = Freq))+
    geom_point(data = pe_cond_l_ch[[1]], 
               mapping = aes(x = X1, y = X2, fill = ct), 
               alpha = 1, pch = 21, size = 4)+
    scale_size_continuous(range = c(0, 4), limits = range(pe_cond_l_ch[[2]]$Freq))+
    scale_alpha_continuous(range = c(0, 1), limits = range(pe_cond_l_ch[[2]]$Freq))+
    #scale_fill_manual(values = colsallct)+
    labs(title = cc)+
    guides(size = guide_legend(direction = "horizontal", nrow = 2),
           alpha = guide_legend(direction = "horizontal", nrow = 2))+
    theme_classic()+ 
    theme(aspect.ratio = 1, 
          axis.line = element_blank(),
          axis.text = element_blank(),
          axis.title = element_blank(),
          axis.ticks = element_blank(),
          panel.background = element_rect(colour = "black"),
          legend.title = element_blank(),
          legend.key.size = unit(0.35, "cm"),
          legend.position = "none")
}
plt_cond_l_ch[["leg"]] = cowplot::get_legend(plt_cond_l_ch[["healthy"]])

pdf("figure_panels_rev1/fig_comm/mainFig_inet_cond_median.pdf", height = 3.2, width = 5, useDingbats = F)
print(plt_cond_l_ch$healthy)
print(plt_cond_l_ch$embolised)
print(plt_cond_l_ch$regenerating)
dev.off()

Network plots with middle cell type resolution - MDS

pltboth = ggplot()+
  geom_point(data = point_cond_df, mapping = aes(x = X1, y = X2, colour = ct2), 
             alpha = 0.6, show.legend = NA, size = 1.3)+
  geom_segment(data = pe_l[[2]], 
               mapping = aes(x = X1.x, xend = X1.y, y = X2.x, yend = X2.y, size = Freq), 
               alpha = 0.15, show.legend = F)+
  geom_point(data = pe_l[[1]], 
             mapping = aes(x = X1, y = X2, fill = ct), 
             alpha = 1, pch = 21, size = 4)+
  guides(colour = guide_legend(override.aes = list(size = 2.3)))+
  scale_size_continuous(range = c(0, 4), limits = range(pe_l[[2]]$Freq))+
  scale_colour_manual(values = colsmajor)+
  #scale_fill_manual(values = colsallct)+
  theme_classic()+ 
  theme(aspect.ratio = 1, 
        axis.line = element_blank(),
        axis.text = element_blank(),
        axis.title = element_blank(),
        axis.ticks = element_blank(),
        legend.title = element_blank(),
        legend.key.size = unit(0.35, "cm"),
        legend.spacing.y = unit(0.1, "cm"),
        legend.position = "none")
pdf("figure_panels_rev1/fig_comm/mainFig_inet_cond_all.pdf", 
    height = 3.1, width = 5.2, useDingbats = F)
print(pltboth)
dev.off()
null device 
          1 
plt_cond_l_ch = list()
for(cc in unique(pe_cond_l_ch[[2]]$condition)){
  plt_cond_l_ch[[cc]] = ggplot()+
    geom_segment(data = pe_cond_l_ch[[2]][pe_cond_l_ch[[2]]$condition==cc,], 
                 mapping = aes(x = X1.x, xend = X1.y, y = X2.x, yend = X2.y, size = Freq, alpha = Freq))+
    geom_point(data = pe_cond_l_ch[[1]], 
               mapping = aes(x = X1, y = X2, fill = ct), 
               alpha = 1, pch = 21, size = 4)+
    scale_size_continuous(range = c(0, 4), limits = range(pe_cond_l_ch[[2]]$Freq))+
    scale_alpha_continuous(range = c(0, 1), limits = range(pe_cond_l_ch[[2]]$Freq))+
    #scale_fill_manual(values = colsallct)+
    labs(title = cc)+
    guides(size = guide_legend(direction = "horizontal", nrow = 2),
           alpha = guide_legend(direction = "horizontal", nrow = 2))+
    theme_classic()+ 
    theme(aspect.ratio = 1, 
          axis.line = element_blank(),
          axis.text = element_blank(),
          axis.title = element_blank(),
          axis.ticks = element_blank(),
          panel.background = element_rect(colour = "black"),
          legend.title = element_blank(),
          legend.key.size = unit(0.35, "cm"),
          legend.position = "none")
}
plt_cond_l_ch[["leg"]] = cowplot::get_legend(plt_cond_l_ch[["healthy"]])

pdf("figure_panels_rev1/fig_comm/mainFig_inet_cond_median.pdf", height = 3.2, width = 5, useDingbats = F)
print(plt_cond_l_ch$healthy)
print(plt_cond_l_ch$embolised)
print(plt_cond_l_ch$regenerating)
dev.off()
null device 
          1 

Network plots - UMAP

pltboth = ggplot()+
  geom_point(data = point_cond_umap_df, mapping = aes(x = X1, y = X2, colour = ct2), 
             alpha = 0.6, show.legend = NA, size = 1.3)+
  geom_segment(data = pe_umap_l[[2]], 
               mapping = aes(x = X1.x, xend = X1.y, y = X2.x, yend = X2.y, size = Freq), 
               alpha = 0.15, show.legend = F)+
  geom_point(data = pe_umap_l[[1]], 
             mapping = aes(x = X1, y = X2, fill = ct), 
             alpha = 1, pch = 21, size = 4)+
  guides(colour = guide_legend(override.aes = list(size = 2.3)))+
  scale_size_continuous(range = c(0, 4), limits = range(pe_l[[2]]$Freq))+
  scale_colour_manual(values = colsmajor)+
  scale_fill_manual(values = colsallct)+
  theme_classic()+ 
  theme(aspect.ratio = 1, 
        axis.line = element_blank(),
        axis.text = element_blank(),
        axis.title = element_blank(),
        axis.ticks = element_blank(),
        legend.title = element_blank(),
        legend.key.size = unit(0.35, "cm"),
        legend.spacing.y = unit(0.1, "cm"),
        legend.position = "none")
pdf("figure_panels_rev1/fig_comm/mainFig_inet_cond_umap_all.pdf", height = 3.1, width = 5.2, useDingbats = F)
print(pltboth)
dev.off()

plt_cond_l_ch = list()
for(cc in unique(pe_umap_cond_l_ch[[2]]$cond)){
  plt_cond_l_ch[[cc]] = ggplot()+
    geom_segment(data = pe_umap_cond_l_ch[[2]][pe_umap_cond_l_ch[[2]]$cond==cc,], 
                 mapping = aes(x = X1.x, xend = X1.y, y = X2.x, yend = X2.y, size = Freq, alpha = Freq))+
    geom_point(data = pe_umap_cond_l_ch[[1]], 
               mapping = aes(x = X1, y = X2, fill = ct), 
               alpha = 1, pch = 21, size = 4)+
    scale_size_continuous(range = c(0, 4), limits = range(pe_umap_cond_l_ch[[2]]$Freq))+
    scale_alpha_continuous(range = c(0, 1), limits = range(pe_umap_cond_l_ch[[2]]$Freq))+
    scale_fill_manual(values = colsallct)+
    labs(title = cc)+
    guides(size = guide_legend(direction = "horizontal", nrow = 2),
           alpha = guide_legend(direction = "horizontal", nrow = 2))+
    theme_classic()+ 
    theme(aspect.ratio = 1, 
          axis.line = element_blank(),
          axis.text = element_blank(),
          axis.title = element_blank(),
          axis.ticks = element_blank(),
          panel.background = element_rect(colour = "black"),
          legend.title = element_blank(),
          legend.key.size = unit(0.35, "cm"),
          legend.position = "none")
}
plt_cond_l_ch[["leg"]] = cowplot::get_legend(plt_cond_l_ch[["healthy"]])

pdf("figure_panels_rev1/fig_comm/mainFig_inet_cond_umap_median.pdf", height = 3.2, width = 5, useDingbats = F)
print(plt_cond_l_ch$healthy)
print(plt_cond_l_ch$embolised)
print(plt_cond_l_ch$regenerating)
dev.off()

Network plots with middle cell type resolution - UMAP

pltboth = ggplot()+
  geom_point(data = point_cond_umap_df, mapping = aes(x = X1, y = X2, colour = ct2), 
             alpha = 0.6, show.legend = NA, size = 1.3)+
  geom_segment(data = pe_umap_l[[2]], 
               mapping = aes(x = X1.x, xend = X1.y, y = X2.x, yend = X2.y, size = Freq), 
               alpha = 0.15, show.legend = F)+
  geom_point(data = pe_umap_l[[1]], 
             mapping = aes(x = X1, y = X2, fill = ct), 
             alpha = 1, pch = 21, size = 4)+
  guides(colour = guide_legend(override.aes = list(size = 2.3)))+
  scale_size_continuous(range = c(0, 4), limits = range(pe_l[[2]]$Freq))+
  scale_colour_manual(values = colsmajor)+
  scale_fill_manual(values = colsallct)+
  theme_classic()+ 
  theme(aspect.ratio = 1, 
        axis.line = element_blank(),
        axis.text = element_blank(),
        axis.title = element_blank(),
        axis.ticks = element_blank(),
        legend.title = element_blank(),
        legend.key.size = unit(0.35, "cm"),
        legend.spacing.y = unit(0.1, "cm"),
        legend.position = "none")
pdf("figure_panels_rev1/fig_comm/mainFig_inet_cond_umap_all.pdf", height = 3.1, width = 5.2, useDingbats = F)
print(pltboth)
dev.off()
null device 
          1 
plt_cond_l_ch = list()
for(cc in unique(pe_umap_cond_l_ch[[2]]$cond)){
  plt_cond_l_ch[[cc]] = ggplot()+
    geom_segment(data = pe_umap_cond_l_ch[[2]][pe_umap_cond_l_ch[[2]]$cond==cc,], 
                 mapping = aes(x = X1.x, xend = X1.y, y = X2.x, yend = X2.y, size = Freq, alpha = Freq))+
    geom_point(data = pe_umap_cond_l_ch[[1]], 
               mapping = aes(x = X1, y = X2, fill = ct), 
               alpha = 1, pch = 21, size = 4)+
    scale_size_continuous(range = c(0, 4), limits = range(pe_umap_cond_l_ch[[2]]$Freq))+
    scale_alpha_continuous(range = c(0, 1), limits = range(pe_umap_cond_l_ch[[2]]$Freq))+
    scale_fill_manual(values = colsallct)+
    labs(title = cc)+
    guides(size = guide_legend(direction = "horizontal", nrow = 2),
           alpha = guide_legend(direction = "horizontal", nrow = 2))+
    theme_classic()+ 
    theme(aspect.ratio = 1, 
          axis.line = element_blank(),
          axis.text = element_blank(),
          axis.title = element_blank(),
          axis.ticks = element_blank(),
          panel.background = element_rect(colour = "black"),
          legend.title = element_blank(),
          legend.key.size = unit(0.35, "cm"),
          legend.position = "none")
}
plt_cond_l_ch[["leg"]] = cowplot::get_legend(plt_cond_l_ch[["healthy"]])

pdf("figure_panels_rev1/fig_comm/mainFig_inet_cond_umap_median.pdf", height = 3.2, width = 5, useDingbats = F)
print(plt_cond_l_ch$healthy)
print(plt_cond_l_ch$embolised)
print(plt_cond_l_ch$regenerating)
dev.off()
null device 
          1 

Heatmaps for interactions with immune cells

# interactions unique to healthy or to emb/regen
comph_inters = c(setdiff(inter_df$healthy$id_cp_interaction,
                         c(inter_df$embolised$id_cp_interaction, inter_df$regenerating$id_cp_interaction)),
                 setdiff(inter_df$embolised$id_cp_interaction, inter_df$healthy$id_cp_interaction),
                 setdiff(inter_df$regenerating$id_cp_interaction, inter_df$healthy$id_cp_interaction))

edge_min = edge_cond_df[,c(1:4,9:12)]
edge_min = merge(edge_min, unique(her_allint_f[,c(1,13)]), by.x = 3, by.y = 1, all.x = T)
edge_min = merge(edge_min, unique(her_allint_f[,c(1,17)]), by.x = 1, by.y = 1, all.x = T)
edge_min = edge_min[edge_min$maj_g1=="Immune" | edge_min$maj_g2=="Immune",]
edge_min = edge_min[edge_min$ct_g1!=edge_min$ct_g2,]
edge_min = edge_min[edge_min$id_cp_interaction %in% comph_inters,]

devdf = filtFunc(her_allint_f[her_allint_f$funct=="development",], expthr = 0.15)
ecmdf = filtFunc(her_allint_f[her_allint_f$funct=="ECM",], expthr = 0.15)

plot_df = filtFunc(her_allint_f[her_allint_f$id_cp_interaction %in% unique(edge_min$id_cp_interaction),],
                   expthr = 0.07, minct = 2)
plot_df = plot_df[!(plot_df$intlr %in% c(devdf$intlr, ecmdf$intlr)),]
imm_plt = pltFunc(plot_df)
pdf("figure_panels_rev1/fig_comm/mainFig_immuneNetInteract_many.pdf", height = 3, width = 20)
print(imm_plt)
dev.off()

plot_df = filtFunc(her_allint_f[her_allint_f$id_cp_interaction %in% unique(edge_min$id_cp_interaction),],
                   expthr = 0.3, minct = 2)
plot_df = plot_df[!(plot_df$intlr %in% c(devdf$intlr, ecmdf$intlr)),]
imm_plt = pltFunc(plot_df)
pdf("figure_panels_rev1/fig_comm/mainFig_immuneNetInteract.pdf", height = 2.86, width = 7.1)
print(imm_plt)
dev.off()

Heatmaps with number of interactions per condition

cnts_list = list()
tab_list = list()
for(n in names(inter_df)[1:3]){
  subdfct = unique(inter_df[[n]][,1:3])
  subdfct$ct1[grepl("LSEC_", subdfct$ct1)] = "LSEC"
  subdfct$ct2[grepl("LSEC_", subdfct$ct2)] = "LSEC"
  subdfct$ct1[grepl("Hepat", subdfct$ct1)] = "Hepatocytes"
  subdfct$ct2[grepl("Hepat", subdfct$ct2)] = "Hepatocytes"
  #subdfct$ct1[grepl("non-", subdfct$ct1)] = "Endothelial cells\n(non-LSEC)"
  #subdfct$ct2[grepl("non-", subdfct$ct2)] = "Endothelial cells\n(non-LSEC)"
  subdfct = unique(subdfct)
  dfct = table(data.frame("ct1" = c(subdfct$ct1, subdfct$ct2),
                          "ct2" = c(subdfct$ct2, subdfct$ct1)))
  hcl = hclust(dist(dfct), method = "ward.D2")
  plot_df = data.frame(dfct)
  plot_df$ct1 = factor(plot_df$ct1, levels = levels(net_names_all$Var1))
  plot_df$ct2 = factor(plot_df$ct2, levels = levels(net_names_all$Var1))
  #plot_df$ct1 = factor(plot_df$ct1, levels = rev(c("Stellate cells", "LSEC", "Endothelial cells\n(non-LSEC)",
  #                                                 "Kupffer cells", "cDCs", "Macrophages", "Cholangiocytes",
  #                                                 "pDCs", "ab-T cells", "Hepatocytes", "gd-T cells", 
  #                                                 "B cells", "Plasmablasts")))
  #plot_df$ct2 = factor(plot_df$ct2, levels = rev(c("Stellate cells", "LSEC", "Endothelial cells\n(non-LSEC)",
  #                                                 "Kupffer cells", "cDCs", "Macrophages", "Cholangiocytes",
  #                                                 "pDCs", "ab-T cells", "Hepatocytes", "gd-T cells", 
  #                                                 "B cells", "Plasmablasts")))
  pltcnts = ggplot(plot_df, aes(x = ct1, y = ct2, size = Freq, colour = Freq))+
    geom_point()+
    labs(x = "cell type", y = "cell type", title = n)+
    guides(colour = guide_legend(title = "# interactions", reverse = T), 
           size = guide_legend(title = "# interactions", reverse = T))+
    scale_colour_gradientn(colors = c("#ededed", "#deebf7", "#9ecae1", "#bcbddc", "#756bb1"), 
                           limits = c(0, 240))+
    scale_size_continuous(limits = c(0, 240))+
    theme_classic()+
    theme(aspect.ratio = 1,
          panel.background = element_rect(colour = "black"),
          axis.line = element_blank(),
          axis.text.x = element_text(angle = 90, hjust = 1, vjust = 0.4),
          axis.text = element_text(colour = "black"))
  cnts_list[[n]] = pltcnts
  tab_list[[n]] = dfct
}
cnts_list$legend = cowplot::get_legend(cnts_list$healthy)
cnts_list$healthy = cnts_list$healthy+theme(legend.position = "none")
cnts_list$embolised = cnts_list$embolised+theme(legend.position = "none")
cnts_list$regenerating = cnts_list$regenerating+theme(legend.position = "none")

pdf("figure_panels_rev1/fig_comm/suppFig_countsCond.pdf", height = 15, width = 15)
cnts_list[[1]]+cnts_list[[3]]+cnts_list[[2]]+cnts_list[[4]]+      patchwork::plot_layout(ncol = 2)
dev.off()

Heatmaps with difference in number of interactions vs healthy

Heatmaps by mid cell type

diff_cnt_l = list()
for(n in c("embolised", "regenerating")){
  dif_df = tab_list[[n]]-tab_list$healthy
  hcl = hclust(dist(dif_df), method = "ward.D2")
  plot_df = data.frame(dif_df)
  #plot_df$ct1 = factor(plot_df$ct1, levels = levels(plot_df$ct1)[hcl$order])
  #plot_df$ct2 = factor(plot_df$ct2, levels = levels(plot_df$ct2)[hcl$order])
  plot_df$ct1 = factor(plot_df$ct1, levels = levels(net_names_all$Var1))
  plot_df$ct2 = factor(plot_df$ct2, levels = levels(net_names_all$Var1))
  #plot_df$ct1 = factor(plot_df$ct1, levels = rev(c("Stellate cells", "LSEC", "Endothelial cells\n(non-LSEC)",
  #                                                 "Kupffer cells", "cDCs", "Macrophages", "Cholangiocytes",
  #                                                 "pDCs", "ab-T cells", "Hepatocytes", "gd-T cells", 
  #                                                 "B cells", "Plasmablasts")))
  #plot_df$ct2 = factor(plot_df$ct2, levels = rev(c("Stellate cells", "LSEC", "Endothelial cells\n(non-LSEC)",
  #                                                 "Kupffer cells", "cDCs", "Macrophages", "Cholangiocytes",
  #                                                 "pDCs", "ab-T cells", "Hepatocytes", "gd-T cells", 
  #                                                 "B cells", "Plasmablasts")))
  pltcnts = ggplot(plot_df[order(plot_df$Freq, decreasing = F),], 
                   aes(x = ct1, y = ct2, size = abs(Freq), colour = Freq))+
    geom_point()+
    labs(x = "cell type", y = "cell type", title = paste0(n, " - healthy"))+
    guides(colour = guide_legend(title = "change in\n# interactions", 
                                 reverse = T, override.aes = list(size = 4)), 
           size = guide_none())+
    scale_colour_gradientn(colors = c("#d7191c", "#fdae61", "#ededed", "#c2a5cf", "#7b3294"), 
                           limits = c(-110, 110))+
    scale_size_continuous(range = c(0.2, 5))+
    theme_classic()+
    theme(aspect.ratio = 1,
          panel.background = element_rect(colour = "black"),
          axis.line = element_blank(),
          axis.text.x = element_text(angle = 90, hjust = 1, vjust = 0.4),
          axis.text = element_text(colour = "black", size = 8))
  print(pltcnts)
  diff_cnt_l[[n]] = pltcnts
}

diff_cnt_l$legend = cowplot::get_legend(diff_cnt_l$embolised)
diff_cnt_l$embolised = diff_cnt_l$embolised+theme(legend.position = "none")
diff_cnt_l$regenerating = diff_cnt_l$regenerating+theme(legend.position = "none")

pdf("figure_panels_rev1/fig_comm/suppFig_countsDiff.pdf", height = 8, width = 15)
print(cowplot::plot_grid(plotlist = diff_cnt_l[c(2,1,3)], ncol = 3, rel_widths = c(1,1,0.3), align = "h"))
Warning: Graphs cannot be horizontally aligned unless the axis parameter is set. Placing graphs unaligned.
dev.off()
png 
  2 

Unique interactions from E and R

print(cowplot::plot_grid(plotlist = diff_cnt_l[c(2,1,3)], 
                         ncol = 3, rel_widths = c(1,1,0.3), align = "hv"))
Warning: Graphs cannot be vertically aligned unless the axis parameter is set. Placing graphs unaligned.
Warning: Graphs cannot be horizontally aligned unless the axis parameter is set. Placing graphs unaligned.

Functions to plot interactions

# number of new unique interactions
## i.e. this ligand-receptor pair was absent at least in healthy and always includes this ct
# get interactions that are not in healthy
inter_h = inter_df$healthy$id_cp_interaction
inter_reg_sub = inter_df$regenerating[!inter_df$regenerating$id_cp_interaction %in% inter_h,
                                      1:3]
inter_emb_sub = inter_df$embolised[!inter_df$embolised$id_cp_interaction %in% inter_h, 1:3]

pve_inter = rbind(inter_reg_sub, inter_emb_sub)
pve_inter$cond = c(rep("regenerating", nrow(inter_reg_sub)),
                   rep("embolised", nrow(inter_emb_sub)))
pve_inter$mid_ct1 = match_df[pve_inter$ct1,"ct_mid"]
pve_inter$mid_ct2 = match_df[pve_inter$ct2,"ct_mid"]

# list unique interactions (all ct)
ct_inter_l = list()
for(cond in unique(pve_inter$cond)){
  ct_inter_l[[cond]] = list()
  sub_pve_inter = pve_inter[pve_inter$cond==cond,]
  sub_pve_inter = sub_pve_inter[sub_pve_inter$ct1!=sub_pve_inter$ct2,]
  
  inter_u = unique(sub_pve_inter$id_cp_interaction)
  for(i in inter_u){
    idf = sub_pve_inter[sub_pve_inter$id_cp_interaction==i, c("ct1", "ct2")]
    tab_int_nu = table(idf$ct1, idf$ct2)
    
    if(nrow(tab_int_nu)==1){
      ct_inter_l[[cond]][[i]] = rownames(tab_int_nu)
    }
    if(ncol(tab_int_nu)==1){
      ct_inter_l[[cond]][[i]] = colnames(tab_int_nu)
    }
  }
  
}
ct_inter_l = reshape2::melt(ct_inter_l)
table(ct_inter_l$value, ct_inter_l$L1)
                            
                             embolised regenerating
  ab-T cells (stress)                3            0
  activated DCs                      0            1
  B cells                            1            1
  Dividing cDCs                      1            1
  Dividing endothelial cells         3            0
  EC non-LSEC                        2            0
  IgA+ Plasma cells                  0            1
  ILC3                               0            2
  Infiltrating NK cells              2            0
  LSEC (fenestr.)                    1            1
  LSEC (interferon)                  0            1
  LSEC (remodelling)                 0            3
  Lymphatic EC                       2            0
  Monocytes (TREM2+ CD9+)            1            1
  pDCs                               4            4
  Stellate cells                    10           17
  Treg                               1            0
# list unique interactions (mid ct)
ctmid_inter_l = list()
ctmid_inter_l_ct = list()
for(cond in unique(pve_inter$cond)){
  ctmid_inter_l[[cond]] = list()
  ctmid_inter_l_ct[[cond]] = list()
  sub_pve_inter = pve_inter[pve_inter$cond==cond,]
  sub_pve_inter = sub_pve_inter[sub_pve_inter$mid_ct1!=sub_pve_inter$mid_ct2,]
  
  inter_u = unique(sub_pve_inter$id_cp_interaction)
  for(i in inter_u){
    idf = sub_pve_inter[sub_pve_inter$id_cp_interaction==i, c("mid_ct1", "mid_ct2")]
    tab_int_nu = table(idf$mid_ct1, idf$mid_ct2)
    mid_ct1_ct = sub_pve_inter[sub_pve_inter$id_cp_interaction==i, "ct1"]
    mid_ct2_ct = sub_pve_inter[sub_pve_inter$id_cp_interaction==i, "ct2"]
    
    if(nrow(tab_int_nu)==1){
      ctmid_inter_l[[cond]][[i]] = rownames(tab_int_nu)
      ctmid_inter_l_ct[[cond]][[i]] = mid_ct1_ct
    }
    if(ncol(tab_int_nu)==1){
      ctmid_inter_l[[cond]][[i]] = colnames(tab_int_nu)
      ctmid_inter_l_ct[[cond]][[i]] = mid_ct2_ct
    }
  }
  
}
ctmid_inter_l = reshape2::melt(ctmid_inter_l)
ctmid_inter_l_ct = unique(reshape2::melt(ctmid_inter_l_ct))
ctmid_inter_l = merge(ctmid_inter_l, ctmid_inter_l_ct, by = c("L2", "L1"), 
                      all = T)[,c(3,1,2,4)]
table(ctmid_inter_l$value.x, ctmid_inter_l$L1)
                
                 embolised regenerating
  B cells                1            2
  Hepatocytes            9            6
  ILC                    2            2
  LSEC                   4            3
  Mesenchymal           10           17
  other ECs              8           10
  other Mono-Mac         2            3
  pDCs                   4            4
  T cells                3            0

Plot all

filtFuncU = function(x, intdf, mutthr = 0, expthr = 0.12, minct = 3){
  coldf = x[,1:8]
  #int_ct_p_t = paste0(intdf$value, intdf$L2)
  coldf$isMain1 = apply(coldf, 1, function(y) paste0(y[2], y[1]) %in% intdf)
  coldf$isMain2 = apply(coldf, 1, function(y) paste0(y[3], y[1]) %in% intdf)
  
  # swap if isMain2
  for(i in 1:nrow(coldf)){
    if(coldf[i,"isMain2"]){
      tmpct = coldf[i,"ct2"]
      tmplr = coldf[i,"lr2"]
      tmpma = coldf[i,"isMain2"]
      
      coldf[i,"ct2"] = coldf[i,"ct1"]
      coldf[i,"lr2"] = coldf[i,"lr1"]
      coldf[i,"isMain2"] = coldf[i,"isMain1"]
      
      coldf[i,"ct1"] = tmpct
      coldf[i,"lr1"] = tmplr
      coldf[i,"isMain1"] = tmpma
    }
  }

  # interaction names
  coldf$intlr = paste0(coldf$lr1, " -\n ", coldf$lr2)
  coldf = unique(coldf[,c(2,3,11,6:10)])
  # interaction frequency
  nint = table(coldf$intlr)
  # expression and interaction filtering
  coldf = coldf[apply(coldf[,4:6], 1, function(x) any(x>=expthr)) & 
                  (coldf$intlr %in% names(nint)[nint>1] | 
                     apply(coldf[,4:6], 1, function(x) any(x>=expthr*8))),]
  # reshaping for plot
  coldf = data.table::rbindlist(list(reshape2::melt(coldf[,c(3,1,4:7)]), 
                                     reshape2::melt(coldf[,c(3,2,4:6, 8)])), use.names = F)
  coldf$variable = unlist(lapply(strsplit(as.character(coldf$variable), "_"), 
                                 function(x) x[1]))
  coldf$variable = factor(coldf$variable, levels = c("healthy","regenerating", "embolised"))
  coldf = coldf[order(coldf$value, decreasing = T),]
  coldf = coldf[!duplicated(coldf[,1:4]),]
  coldf$ct1 = gsub("Endothelial cells", "EC", coldf$ct1)
  coldf$intlr = gsub("receptor", "rec", coldf$intlr)
  coldf$intlr = gsub("complex", "comp", coldf$intlr)
  nct = table(coldf$ct1)
  coldf = coldf[coldf$ct1 %in% names(nct)[nct>=minct*3],]
  nint = table(coldf$intlr)
  coldf = coldf[coldf$intlr %in% names(nint)[nint>3],]
  
  # confirm that all interactions have at least one TRUE
  ntrue = tapply(coldf$isMain1, coldf$intlr, sum)
  coldf = coldf[coldf$intlr %in% names(ntrue)[ntrue>0]]
  
  # formatting
  coldf = coldf[order(coldf$isMain1, coldf$intlr, -coldf$value, decreasing = T),]
  coldf$ct1 = factor(coldf$ct1, levels = rev(unique(coldf$ct1)))
  coldf$intlr = factor(coldf$intlr, levels = rev(unique(coldf$intlr)))
  coldf = coldf[order(coldf$isMain1, decreasing = F),]
  
  return(coldf)
}

pltFuncU = function(x){
  plt = ggplot(x, aes(y = ct1, x = variable, fill = value, colour = isMain1))+
    facet_grid(intlr~., scales = "free_y", space = "free_y")+
    geom_tile(size = 0.4)+
    scale_x_discrete(expand = c(0,0))+
    scale_fill_gradientn(colors = gradexpcol)+
    scale_colour_manual(values = c("white", "black"))+
    guides(fill = guide_colourbar(barheight = unit(0.4, "cm")),
           colour = guide_none())+
    labs(x = "Condition", y = "Cell type", fill = "mean exp")+
    theme_classic()+
    theme(axis.text.y = element_text(colour = "black", size = 7, 
                                     angle = 0, hjust = 1, vjust = 0.5),
          axis.text.x = element_text(colour = "black", size = 6.5, 
                                     angle = 35, hjust=1, vjust=1),
          axis.title = element_text(size = 7),
          axis.line = element_blank(),
          legend.position = "bottom",
          legend.title = element_text(size = 7),
          legend.box.margin = margin(0,0,0,0),
          legend.text = element_text(size = 6),
          strip.text.y = element_text(angle = 0, size = 7, margin = margin(0,0,3,0), 
                                      hjust = 0.5, vjust = 0.5, face = "bold"),
          strip.background = element_blank())
  return(plt)
}

Plot one by one

plot_df = filtFuncU(her_allint_f[her_allint_f$id_cp_interaction %in% ct_inter_l$L2[!grepl("stress", ct_inter_l$value)],],
                    intdf = paste0(ct_inter_l$value, ct_inter_l$L2), 
                    expthr = 0.2, minct = 1)
Using intlr, ct1, isMain1 as id variables
Using intlr, ct2, isMain2 as id variables
imm_plt = pltFuncU(plot_df)
pdf("figure_panels_rev1/fig_comm/mainFig_InteractUnique.pdf", 
    height = 20, width = 2.8)
print(imm_plt)
dev.off()
null device 
          1 
plot_df = filtFuncU(her_allint_f[her_allint_f$id_cp_interaction %in% ctmid_inter_l$L2[!grepl("stress", ctmid_inter_l$value.y)],],
                   intdf = paste0(ctmid_inter_l$value.y, ctmid_inter_l$L2), 
                   expthr = 0.2, minct = 3)
Using intlr, ct1, isMain1 as id variables
Using intlr, ct2, isMain2 as id variables
imm_plt = pltFuncU(plot_df)
pdf("figure_panels_rev1/fig_comm/mainFig_InteractUnique_mid.pdf", 
    height = 32, width = 2.8)
print(imm_plt)
dev.off()
null device 
          1 

Plot one by one, all in H vs PVE network

plot_df = filtFuncU(her_allint_f[her_allint_f$id_cp_interaction %in% ct_inter_l$L2[!grepl("stress", ct_inter_l$value)],],
                    intdf = paste0(ct_inter_l$value, ct_inter_l$L2), 
                    expthr = 0.2, minct = 3)
Using intlr, ct1, isMain1 as id variables
Using intlr, ct2, isMain2 as id variables
folder = "figure_panels_rev1/fig_comm/heatmaps_interact_indiv/"
for(i in 1:length(unique(plot_df$intlr))){
  iii = unique(plot_df$intlr)[i]
  sub_plot_df = plot_df[plot_df$intlr==iii,]
  sub_plot_df = sub_plot_df[order(sub_plot_df$isMain1, sub_plot_df$value, decreasing = T),]
  sub_plot_df$ct1 = factor(sub_plot_df$ct1, levels = rev(unique(sub_plot_df$ct1)))
  sub_plot_df = sub_plot_df[order(sub_plot_df$isMain1, decreasing = F),]
  
  pdf(paste0(folder, "mainFig_InteractUnique_", i, ".pdf"), height = 3, width = 4)
  print(pltFuncU(sub_plot_df))
  dev.off()
}

plot_df = filtFuncU(her_allint_f[her_allint_f$id_cp_interaction %in% ctmid_inter_l$L2[!grepl("stress", ctmid_inter_l$value.y)],],
                   intdf = paste0(ctmid_inter_l$value.y, ctmid_inter_l$L2), 
                   expthr = 0.2, minct = 3)
Using intlr, ct1, isMain1 as id variables
Using intlr, ct2, isMain2 as id variables
folder = "figure_panels_rev1/fig_comm/heatmaps_interact_indiv/"
for(i in 1:length(unique(plot_df$intlr))){
  iii = unique(plot_df$intlr)[i]
  sub_plot_df = plot_df[plot_df$intlr==iii,]
  sub_plot_df = sub_plot_df[order(sub_plot_df$isMain1, sub_plot_df$value, decreasing = T),]
  sub_plot_df$ct1 = factor(sub_plot_df$ct1, levels = rev(unique(sub_plot_df$ct1)))
  sub_plot_df = sub_plot_df[order(sub_plot_df$isMain1, decreasing = F),]
  
  pdf(paste0(folder, "mainFig_InteractUnique_mid_", i, ".pdf"), height = 3, width = 2.8)
  print(pltFuncU(sub_plot_df))
  dev.off()
}

Plot changes in number of interactions per condition - mid resolution

plot_df = filtFunc(her_allint_f[her_allint_f$id_cp_interaction %in% unique(edge_min$id_cp_interaction),],
                   expthr = 0.15, minct = 2)
Using intlr, ct1 as id variables
Using intlr, ct2 as id variables

Panels cirrhosis

UMAP Immune cells

UMAP Mono/Mac cells

m_df = readRDS(file = "results/cirrhosis/umap_m_df.RDS")

cols = MetBrewer::met.brewer("Klimt", length(unique(m_df$all_annot)))
names(cols) = unique(m_df$all_annot)

m_df = m_df[sample(1:nrow(m_df), nrow(m_df), replace = F),]
plt = ggplot()+
  geom_point(aes(x = UMAP_1, y = UMAP_2, colour = all_annot), 
             m_df, size = 0.2)+
  guides(colour = guide_legend(override.aes = list(size = 3)))+
  scale_colour_manual(values = cols[order(names(cols))])+
  theme_void()+
  theme(aspect.ratio = 1,
        legend.text = element_text(size = 6),
        legend.key.size = unit(0.4, "cm"),
        legend.title = element_blank())

pdf("figure_panels_rev1/fig_cir/all_mono_umap.pdf", height = 2.2, width = 4.2)
print(plt)
dev.off()

UMAP T/NK cells

t_df = readRDS(file = "results/cirrhosis/umap_t_df.RDS")

cols = MetBrewer::met.brewer("Juarez", length(unique(t_df$all_annot)))
names(cols) = unique(t_df$all_annot)

t_df = t_df[sample(1:nrow(t_df), nrow(t_df), replace = F),]
plt = ggplot()+
  geom_point(aes(x = UMAP_1, y = UMAP_2, colour = all_annot), 
             t_df, size = 0.2)+
  guides(colour = guide_legend(override.aes = list(size = 3)))+
  scale_colour_manual(values = cols[order(names(cols))])+
  theme_void()+
  theme(aspect.ratio = 1,
        legend.text = element_text(size = 6),
        legend.key.size = unit(0.375, "cm"),
        legend.title = element_blank())

pdf("figure_panels_rev1/fig_cir/all_tnk_umap.pdf", height = 2.2, width = 4.2)
print(plt)
dev.off()

Markers myeloid cells

mat_m = readRDS(file = "results/cirrhosis/mat_myeloid_markers.RDS")

cols_pal = colorRampPalette(rev(brewer.pal(n = 9, name = "RdBu")))(100)

pdf("figure_panels_rev1/fig_cir/heat_mk_mye.pdf", height = 2.2, width = 6.3)
pheatmap::pheatmap(mat_m, clustering_method = "ward.D", color = cols_pal,
                   treeheight_col = 0, treeheight_row = 20, fontsize = 6.3)
dev.off()

Markers lymphoid cells

mat_l = readRDS("results/cirrhosis/mat_lymphoid_markers.RDS")

cols_pal = colorRampPalette(rev(brewer.pal(n = 9, name = "RdBu")))(100)

pdf("figure_panels_rev1/fig_cir/heat_mk_lym.pdf", height = 2.2, width = 6.3)
pheatmap::pheatmap(mat_l, clustering_method = "ward.D", color = cols_pal,
                   treeheight_col = 0, treeheight_row = 20, fontsize = 6.3)
dev.off()

Proportions immune cells

imm_props = readRDS(file = "results/cirrhosis/imm_props_dat.RDS")
imm_pvals = readRDS("results/cirrhosis/imm_props_pval.RDS")

plt = ggplot(imm_props, aes(x = Condition, y = Freq, group = Condition, colour = Condition))+
  facet_wrap(~Var1, scales = "free")+
  geom_jitter(position = position_jitterdodge(jitter.width = 0.3, dodge.width = 1))+
  stat_summary(fun.data = mean_se, position = position_dodge(width = 1), 
               alpha = 0.35, colour = "black")+
  theme_bw()+
  theme(legend.position = "none")


colnames(imm_pvals)[1] = "embolized"

imm_props$Condition[imm_props$Condition=="embolised"] = "embolized"
imm_props$Condition = factor(imm_props$Condition, 
                             levels = c("healthy", "regenerating", "embolized"))

pval_pos = imm_props %>%
  group_by(Condition, Var1) %>%
  summarise_at(vars("Freq"), mean)
pval_pos$posy = pval_pos$Freq*1.02
pval_pos$posx = as.numeric(pval_pos$Condition)+0.3
pval_pos = pval_pos[pval_pos$Condition!="healthy",]
pval_pos$pval = diag(as.matrix(imm_pvals[pval_pos$Var1,as.character(pval_pos$Condition)]))
pval_pos$issig = ifelse(pval_pos$pval<=0.05, "*", "")

plt = ggplot()+
  facet_wrap(~Var1, scales = "free")+
  geom_jitter(data = imm_props, mapping = aes(x = Condition, y = Freq, 
                                              group = Condition, colour = Condition),
              position = position_jitterdodge(jitter.width = 0.3, dodge.width = 1), size = 0.5)+
  stat_summary(data = imm_props, mapping = aes(x = Condition, y = Freq, 
                                              group = Condition, colour = Condition),
               fun.data = mean_se, position = position_dodge(width = 1), 
               alpha = 0.6, colour = "black", size = 0.25)+
  geom_text(data = pval_pos, mapping = aes(x = posx, y = posy, label = issig), size = 4)+
  scale_colour_manual(values = colcond, drop = T, limits = names(colcond)[c(1,2,4)])+
  scale_x_discrete(labels = c("H", "R", "E"))+
  labs(y = "proportion % (immune)")+
  theme_bw()+
  theme(legend.position = "none",
        axis.title = element_text(size = 6, colour = "black"),
        axis.text.x = element_text(size = 6, colour = "black"),
        axis.text.y = element_text(size = 6, colour = "black"),
        strip.text = element_text(size = 6),
        strip.background = element_rect(fill = "white"),
        panel.grid.minor = element_blank(),
        panel.grid.major.x = element_blank(),
        panel.grid.major.y = element_line(size = 0.3, colour = "grey70"))

#pdf("figure_panels_rev1/fig_cir/immune_all_prop.pdf", height = 7.5, width = 11.5)
print(plt)
#dev.off()

pdf("figure_panels_rev1/fig_cir/immune_all_prop_resized.pdf", height = 5.5, width = 7)
print(plt)
dev.off()

Proportions endothelial cells

plt = ggplot()+
  facet_wrap(~Var1, scales = "free")+
  geom_jitter(data = imm_props, mapping = aes(x = Condition, y = Freq, 
                                              group = Condition, colour = Condition),
              position = position_jitterdodge(jitter.width = 0.3, dodge.width = 1), size = 0.5)+
  stat_summary(data = imm_props, mapping = aes(x = Condition, y = Freq, 
                                              group = Condition, colour = Condition),
               fun.data = mean_se, position = position_dodge(width = 1), 
               alpha = 0.6, colour = "black", size = 0.25)+
  geom_text(data = pval_pos, mapping = aes(x = posx, y = posy, label = issig), size = 4)+
  scale_colour_manual(values = colcond, drop = T, limits = names(colcond)[c(1,2,4)])+
  scale_x_discrete(labels = c("H", "R", "E"))+
  labs(y = "proportion % (immune)")+
  theme_bw()+
  theme(legend.position = "none",
        axis.title = element_text(size = 6, colour = "black"),
        axis.text.x = element_text(size = 6, colour = "black"),
        axis.text.y = element_text(size = 6, colour = "black"),
        strip.text = element_text(size = 6),
        strip.background = element_rect(fill = "white"),
        panel.grid.minor = element_blank(),
        panel.grid.major.x = element_blank(),
        panel.grid.major.y = element_line(size = 0.3, colour = "grey70"))

#pdf("figure_panels_rev1/fig_cir/immune_all_prop.pdf", height = 7.5, width = 11.5)
print(plt)
#dev.off()

pdf("figure_panels_rev1/fig_cir/immune_all_prop_resized.pdf", height = 5.5, width = 7)
print(plt)
dev.off()
png 
  2 

MP signatures

mp_sig_df = readRDS(file = "results/cirrhosis/mono_cirr_ct_signatures.RDS")

plot_df = reshape2::melt(mp_sig_df)
plot_df$Condition[plot_df$Condition=="embolised"] = "embolized"
plot_df$Condition = factor(plot_df$Condition, 
                           levels = c("healthy","regenerating","embolized"))
sub_plot_df = plot_df[plot_df$variable %in% c("cirr_ct_MPs_4","cirr_ct_MPs_5"),]
sub_plot_df$variable = gsub("cirr_ct_MPs_4", "SAMac (1)", sub_plot_df$variable)
sub_plot_df$variable = gsub("cirr_ct_MPs_5", "SAMac (2)", sub_plot_df$variable)

plt = ggplot(sub_plot_df, aes(x = mono_annot, y = value, fill = Condition))+
  facet_grid(variable~mono_annot, scales = "free")+
  geom_hline(yintercept = 0, linetype = "dashed", size = 0.3)+
  geom_violin(scale = "count")+
  scale_fill_manual(values = colcond, drop = T, limits = names(colcond)[c(1,2,4)])+
  theme_classic()+
  theme(axis.text.x = element_blank(),
        axis.title.x = element_blank(),
        axis.ticks.x = element_blank(),
        axis.text.y = element_text(size = 6, colour = "black"),
        axis.title.y = element_text(size = 6.5),
        strip.text = element_text(size = 7),
        panel.border = element_rect(colour = "black", fill = NA),
        axis.line = element_blank(),
        legend.position = c(0.048, 0.865),
        legend.background = element_blank(),
        legend.key.size = unit(0.3, "cm"),
        legend.text = element_text(size = 6.5),
        legend.title = element_text(size = 7))

pdf("figure_panels_rev1/fig_cir/mp_sig_vio.pdf", height = 3, width = 10.35)
print(plt)
dev.off()

Endothelial signatures

mp_sig_df = readRDS(file = "results/cirrhosis/mono_cirr_ct_signatures.RDS")

plot_df = reshape2::melt(mp_sig_df)
Using Condition, mono_annot as id variables
plot_df$Condition[plot_df$Condition=="embolised"] = "embolized"
plot_df$Condition = factor(plot_df$Condition, 
                           levels = c("healthy","regenerating","embolized"))
sub_plot_df = plot_df[plot_df$variable %in% c("cirr_ct_MPs_4","cirr_ct_MPs_5"),]
sub_plot_df$variable = gsub("cirr_ct_MPs_4", "SAMac (1)", sub_plot_df$variable)
sub_plot_df$variable = gsub("cirr_ct_MPs_5", "SAMac (2)", sub_plot_df$variable)

plt = ggplot(sub_plot_df, aes(x = mono_annot, y = value, fill = Condition))+
  facet_grid(variable~mono_annot, scales = "free")+
  geom_hline(yintercept = 0, linetype = "dashed", size = 0.3)+
  geom_violin(scale = "count")+
  scale_fill_manual(values = colcond, drop = T, limits = names(colcond)[c(1,2,4)])+
  theme_classic()+
  theme(axis.text.x = element_blank(),
        axis.title.x = element_blank(),
        axis.ticks.x = element_blank(),
        axis.text.y = element_text(size = 6, colour = "black"),
        axis.title.y = element_text(size = 6.5),
        strip.text = element_text(size = 7),
        panel.border = element_rect(colour = "black", fill = NA),
        axis.line = element_blank(),
        legend.position = c(0.048, 0.865),
        legend.background = element_blank(),
        legend.key.size = unit(0.3, "cm"),
        legend.text = element_text(size = 6.5),
        legend.title = element_text(size = 7))

pdf("figure_panels_rev1/fig_cir/mp_sig_vio.pdf", height = 3, width = 10.35)
print(plt)
dev.off()
null device 
          1 

Hepatocyte signatures

end_sig_df = readRDS(file = "results/cirrhosis/endo_cirr_ct_signatures.RDS")

plot_df = reshape2::melt(end_sig_df)
Using Condition, endo_simp as id variables
plot_df$Condition[plot_df$Condition=="embolised"] = "embolized"
plot_df$Condition[plot_df$Condition=="embolised"] = "embolized"
plot_df$Condition = factor(plot_df$Condition, 
                           levels = c("healthy","regenerating","embolized"))
sub_plot_df = plot_df[plot_df$variable %in% c("cirr_ct_Endothelia_6","cirr_ct_Endothelia_7"),]
sub_plot_df$variable = gsub("cirr_ct_Endothelia_6", 
                            "SAEndothelial (1)", sub_plot_df$variable)
sub_plot_df$variable = gsub("cirr_ct_Endothelia_7", "SAEndothelial (2)",
                            sub_plot_df$variable)

plt = ggplot(sub_plot_df, aes(x = endo_simp, y = value, fill = Condition))+
  facet_grid(variable~endo_simp, scales = "free")+
  geom_hline(yintercept = 0, linetype = "dashed", size = 0.3)+
  geom_violin(scale = "count")+
  scale_fill_manual(values = colcond, drop = T, limits = names(colcond)[c(1,2,4)])+
  theme_classic()+
  theme(axis.text.x = element_blank(),
        axis.title.x = element_blank(),
        axis.ticks.x = element_blank(),
        axis.text.y = element_text(size = 6, colour = "black"),
        axis.title.y = element_text(size = 6.5),
        strip.text = element_text(size = 7),
        panel.border = element_rect(colour = "black", fill = NA),
        axis.line = element_blank(),
        legend.position = "bottom",
        legend.background = element_blank(),
        legend.margin = margin(0,0,0,0),
        legend.key.size = unit(0.3, "cm"),
        legend.text = element_text(size = 6.5),
        legend.title = element_text(size = 7))

pdf("figure_panels_rev1/fig_cir/endo_sig_vio.pdf", height = 2.8, width = 11)
print(plt)
dev.off()
null device 
          1 
LS0tCnRpdGxlOiAiRmlndXJlIFBsb3R0aW5nIFJldjEiCm91dHB1dDogaHRtbF9ub3RlYm9vawotLS0KCk5vdGVib29rIHRvIG1ha2UgdGhlIHBhbmVscyBmb3IgdGhlIHBhcGVyIGZpZ3VyZXMgYWZ0ZXIgcmV2aXNpb24KCiMgR2VuZXJhbCBTZXR1cApTZXR1cCBjaHVuawoKYGBge3IsIHNldHVwLCBpbmNsdWRlPUZBTFNFfQprbml0cjo6b3B0c19jaHVuayRzZXQoZmlnLndpZHRoID0gOCkKa25pdHI6Om9wdHNfa25pdCRzZXQocm9vdC5kaXIgPSBub3JtYWxpemVQYXRoKCIuLiIpKQprbml0cjo6b3B0c19rbml0JGdldCgicm9vdC5kaXIiKQpgYGAKCkxvYWQgbGlicmFyaWVzCgpgYGB7cn0KbGlicmFyeShkcGx5cikKbGlicmFyeShTZXVyYXQpCmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeShnZ3JlcGVsKQpsaWJyYXJ5KGdncmlkZ2VzKQpsaWJyYXJ5KHBoZWF0bWFwKQpsaWJyYXJ5KFJDb2xvckJyZXdlcikKbGlicmFyeShNZXRCcmV3ZXIpCmBgYAoKRGVmaW5lIHBsb3QgdGhlbWUocykKCmBgYHtyfQp0aF9nZW4gPSB0aGVtZShheGlzLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDcsIGNvbG91ciA9ICJibGFjayIpLAogICAgICAgICAgICAgICBheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSA4LCBjb2xvdXIgPSAiYmxhY2siKSwKICAgICAgICAgICAgICAgYXhpcy5saW5lID0gZWxlbWVudF9saW5lKGNvbG91ciA9ICJibGFjayIpLAogICAgICAgICAgICAgICBwbG90LmJhY2tncm91bmQgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgICAgICAgIGF4aXMudGlja3MgPSBlbGVtZW50X2JsYW5rKCksIAogICAgICAgICAgICAgICBwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgICAgICAgICBwYW5lbC5ncmlkID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgICAgICAgICBsZWdlbmQuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSwgCiAgICAgICAgICAgICAgIGxlZ2VuZC5rZXkuc2l6ZSA9IHVuaXQoMC4zNSwgImNtIiksCiAgICAgICAgICAgICAgIGxlZ2VuZC5rZXkgPSBlbGVtZW50X2JsYW5rKCksIGxlZ2VuZC5zcGFjaW5nID0gdW5pdCgwLjcsICJjbSIpLAogICAgICAgICAgICAgICBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gOSksCiAgICAgICAgICAgICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTApLAogICAgICAgICAgICAgICBsZWdlbmQuYm94Lm1hcmdpbiA9IG1hcmdpbigwLjEsMC4xLDAuMSwwLjEpLAogICAgICAgICAgICAgICBsZWdlbmQuYm94LnNwYWNpbmcgPSB1bml0KDAuNSwiY20iKSkKcG9pbnRzaXplID0gMC4zCnRoZW1lX3NldCh0aF9nZW4pCmBgYAoKVXNlZnVsIGZ1bmN0aW9ucwoKYGBge3J9CmJyZWFrU3RyID0gZnVuY3Rpb24ocywgbiA9IDIwKSB7cmV0dXJuKGdzdWIocGFzdGUwKCcoLnsxLCcsYXMuY2hhcmFjdGVyKG4pLCd9KShcXHN8JCknKSwgJ1xcMVxuJywgcykpfQoKZ2V0VG9wVGVybXMgPSBmdW5jdGlvbihnb2RmLCB0b3B0ID0gMTAwLCBuY2wgPSA1LCBudCA9IDIpewogIHRvcHQgPSBpZihucm93KGdvZGYpPHRvcHQpIG5yb3coZ29kZikgZWxzZSB0b3B0CiAgaWYobnJvdyhnb2RmKTxuY2wpIHJldHVybihnb2RmKQogIGRmID0gZ29kZlsxOnRvcHQsXQogIGdlbmVzID0gc2FwcGx5KGRmJGdlbmVJRCwgZnVuY3Rpb24oeCkgc3Ryc3BsaXQoeCwgIi8iKSkKICByZXNtYXQgPSBtYXRyaXgoMCwgbGVuZ3RoKGdlbmVzKSwgbGVuZ3RoKGdlbmVzKSkKICBmb3IoaSBpbiAxOmxlbmd0aChnZW5lcykpewogICAgZm9yKGogaW4gMTpsZW5ndGgoZ2VuZXMpKXsKICAgICAgcmVzbWF0W2ksal0gPSBsZW5ndGgoaW50ZXJzZWN0KGdlbmVzW1tpXV0sIGdlbmVzW1tqXV0pKS9sZW5ndGgoZ2VuZXNbW2ldXSkKICAgIH0KICB9CiAgY2wgPSBoY2x1c3QoZGlzdChyZXNtYXQpLCBtZXRob2QgPSAid2FyZC5EMiIpCiAgY2wgPSBjdXRyZWUoY2wsIG5jbCkKICByZXNfZGYgPSBkYXRhLmZyYW1lKCJEZXNjcmlwdGlvbiIgPSBkZiREZXNjcmlwdGlvbiwgInF2YWx1ZSIgPSBkZiRxdmFsdWUsIGNsLCAKICAgICAgICAgICAgICAgICAgICAgICJnZW5lSUQiID0gdW5saXN0KGRmJGdlbmVJRCksIHN0cmluZ3NBc0ZhY3RvcnMgPSBGKQogIHJlc19kZiA9IHJlc19kZltvcmRlcihyZXNfZGYkcXZhbHVlLCBkZWNyZWFzaW5nID0gRiksXQogIHRvcHRlcm1zID0gdW5saXN0KHRhcHBseShyZXNfZGYkRGVzY3JpcHRpb24sIHJlc19kZiRjbCwgZnVuY3Rpb24oeCkgeFsxOm50XSkpCiAgcmVzX2RmID0gcmVzX2RmW3Jlc19kZiREZXNjcmlwdGlvbiAlaW4lIHRvcHRlcm1zLF0KICAKICByZXR1cm4ocmVzX2RmKQp9CgpnZXRUb3BUZXJtc1BhaXJlZCA9IGZ1bmN0aW9uKGdvZGYsIGdlbmVzY29sID0gImdlbmVzX2FsbCIsIG5jbCA9IDUsIG50ID0gMil7CiAgaWYobnJvdyhnb2RmKTxuY2wpIHJldHVybihnb2RmKQogIGdlbmVzID0gc2FwcGx5KGdvZGZbLGdlbmVzY29sXSwgZnVuY3Rpb24oeCkgc3Ryc3BsaXQoeCwgIi8iKSkKICByZXNtYXQgPSBtYXRyaXgoMCwgbGVuZ3RoKGdlbmVzKSwgbGVuZ3RoKGdlbmVzKSkKICBmb3IoaSBpbiAxOmxlbmd0aChnZW5lcykpewogICAgZm9yKGogaW4gMTpsZW5ndGgoZ2VuZXMpKXsKICAgICAgcmVzbWF0W2ksal0gPSBsZW5ndGgoaW50ZXJzZWN0KGdlbmVzW1tpXV0sIGdlbmVzW1tqXV0pKS9sZW5ndGgoZ2VuZXNbW2ldXSkKICAgIH0KICB9CiAgY2wgPSBoY2x1c3QoZGlzdChyZXNtYXQpLCBtZXRob2QgPSAid2FyZC5EMiIpCiAgY2wgPSBjdXRyZWUoY2wsIG5jbCkKICByZXNfZGYgPSBkYXRhLmZyYW1lKCJEZXNjcmlwdGlvbiIgPSBnb2RmJERlc2NyaXB0aW9uLCAicXZhbF9lbWJvbGl6ZWQiID0gZ29kZiRxdmFsX2VtYm9saXplZCwgCiAgICAgICAgICAgICAgICAgICAgICAicXZhbF9yZWdlbmVyYXRpbmciID0gZ29kZiRxdmFsX3JlZ2VuZXJhdGluZywgCiAgICAgICAgICAgICAgICAgICAgICAiZ2VuZXNfZW1ib2xpemVkIiA9IHVubGlzdChnb2RmJGdlbmVzX2VtYm9saXplZCksIAogICAgICAgICAgICAgICAgICAgICAgImdlbmVzX3JlZ2VuZXJhdGluZyIgPSB1bmxpc3QoZ29kZiRnZW5lc19yZWdlbmVyYXRpbmcpLAogICAgICAgICAgICAgICAgICAgICAgY2wsIHN0cmluZ3NBc0ZhY3RvcnMgPSBGKQogIHJlc19kZiRxdmFsX21heCA9IGFwcGx5KHJlc19kZlssYygicXZhbF9lbWJvbGl6ZWQiLCJxdmFsX3JlZ2VuZXJhdGluZyIpXSwgMSwgZnVuY3Rpb24oeCkgbWluKHgpKQogIHJlc19kZiA9IHJlc19kZltvcmRlcihyZXNfZGYkcXZhbF9tYXgsIGRlY3JlYXNpbmcgPSBGKSxdCiAgdG9wdGVybXMgPSB1bmxpc3QodGFwcGx5KHJlc19kZiREZXNjcmlwdGlvbiwgcmVzX2RmJGNsLCBmdW5jdGlvbih4KSB4WzE6bnRdKSkKICByZXNfZGYgPSByZXNfZGZbcmVzX2RmJERlc2NyaXB0aW9uICVpbiUgdG9wdGVybXMsXQogIAogIHJldHVybihyZXNfZGYpCn0KCnJwZmlsdGVyID0gZnVuY3Rpb24oeCl7CiAgcmV0dXJuKCFncmVwbCgiXlJQTCIsIHgkZ2VuZUlEKSAmICFncmVwbCgiXlJQUyIsIHgkZ2VuZUlEKSAmIAogICAgICAgICAgICFncmVwbCgiL1JQTCIsIHgkZ2VuZUlELCBmaXhlZCA9IFQpICYgIWdyZXBsKCIvUlBTIiwgeCRnZW5lSUQsIGZpeGVkID0gVCkpCn0KYGBgCgpDb2xvdXIgcGFsZXR0ZXMKCmBgYHtyfQpjb2xzbWFqb3IgPSBjKCJDaG9sYW5naW9jeXRlcyIgPSAiYmlzcXVlMiIsICJFbmRvdGhlbGlhbCIgPSAiYXF1YW1hcmluZTQiLCAgCiAgICAgICAgICAgICAgIkhlcGF0b2N5dGVzIiA9ICJ0b21hdG8zIiwgIkltbXVuZSIgPSAic2t5Ymx1ZSIsIAogICAgICAgICAgICAgICJNZXNlbmNoeW1hbCIgPSAic2FuZHlicm93biIsICJEb3VibGV0cyIgPSAiZ3JleTkwIikKY29sY29uZCA9IGMoImhlYWx0aHkiID0gIm9yYW5nZSIsICJyZWdlbmVyYXRpbmciID0gInNhbG1vbiIsIAogICAgICAgICAgICAiZW1ib2xpc2VkIiA9ICJkYXJrcmVkIiwgImVtYm9saXplZCIgPSAiZGFya3JlZCIpCmNvbGRvbiA9IGMoInNjX0gxIiA9ICJwbHVtNCIsICJzY19IMiIgPSAic2FsbW9uNCIsICJzY19IMyIgPSAibGlnaHRzYWxtb24zIikKY29sZG9uYWxsID0gYygic2NfSDEiID0gInBsdW00IiwgInNjX0gyIiA9ICJzYWxtb240IiwgInNjX0gzIiA9ICJsaWdodHNhbG1vbjMiLCAKICAgICAgICAgICAgICAic2NfRTEiID0gImRhcmtvcmFuZ2UzIiwgInNjX1IxIiA9ICJkYXJrb3JhbmdlMyIsICJzY19FMiIgPSAiZ29sZGVucm9kMyIsIAogICAgICAgICAgICAgICJzY19SMiIgPSAiZ29sZGVucm9kMyIsICAic2NfRTMiID0gIm1lZGl1bW9yY2hpZCIsICJzY19SMyIgPSAibWVkaXVtb3JjaGlkIiwgCiAgICAgICAgICAgICAgInNjX0U0IiA9ICJwbHVtMiIsICJzY19SNCIgPSAicGx1bTIiLCAic2NfRTUiID0gInBhbGV2aW9sZXRyZWQzIiwgCiAgICAgICAgICAgICAgInNjX1I1IiA9ICJwYWxldmlvbGV0cmVkMyIsICJzY19FNiIgPSAicGVhY2hwdWZmMiIsICJzY19SNiIgPSAicGVhY2hwdWZmMiIsCiAgICAgICAgICAgICAgInNjX0UxL3NjX1IxIiA9ICJkYXJrb3JhbmdlMyIsICJzY19FMi9zY19SMiIgPSAiZ29sZGVucm9kMyIsIAogICAgICAgICAgICAgICJzY19FMy9zY19SMyIgPSAibWVkaXVtb3JjaGlkIiwgInNjX0U0L3NjX1I0IiA9ICJwbHVtMiIsIAogICAgICAgICAgICAgICJzY19FNS9zY19SNSIgPSAicGFsZXZpb2xldHJlZDMiLCAic2NfRTYvc2NfUjYiID0gInBlYWNocHVmZjIiKQoKY29sc2FsbGN0ID0gYygiQ2hvbGFuZ2lvY3l0ZXMiID0gImJpc3F1ZTIiLCAiSGVwYXRvY3l0ZXMiID0gInRvbWF0bzMiLCAiU3RlbGxhdGUgY2VsbHMiID0gInNhbmR5YnJvd24iLCAKICAgICAgICAgICAgICAiRG91YmxldHMiID0gImdyZXk5MCIsICJMU0VDIHBlcmljZW50cmFsIiA9ICJhcXVhbWFyaW5lNCIsICJMU0VDIHBlcmlwb3J0YWwiID0gImFxdWFtYXJpbmUyIiwgCiAgICAgICAgICAgICAgIkVuZG90aGVsaWFsIGNlbGxzIChub24tTFNFQykiID0gImZvcmVzdGdyZWVuIiwgIlBsYXNtYWJsYXN0cyIgPSAiZGFya29yY2hpZDQiLAogICAgICAgICAgICAgICJLdXBmZmVyIGNlbGxzIiA9ICJza3libHVlMSIsICJhYi1UIGNlbGxzIiA9ICJsaWdodHNreWJsdWUzIiwgImdkLVQgY2VsbHMiID0gImNvcm5mbG93ZXJibHVlIiwKICAgICAgICAgICAgICAiQiBjZWxscyIgPSAiZGFya29yY2hpZDEiLCAiY0RDcyIgPSAiZGVlcHNreWJsdWUxIiwgInBEQ3MiID0gInJveWFsYmx1ZTMiLCAKICAgICAgICAgICAgICAiTWFjcm9waGFnZXMiID0gInN0ZWVsYmx1ZTMiLCAiRGl2aWRpbmcgY2VsbHMiID0gImdyZXkzNSIsICJMU0VDIiA9ICJhcXVhbWFyaW5lMyIpCmNvbHN1YiA9IGMoInJvc3licm93bjQiLCJ0aGlzdGxlNCIsInRoaXN0bGUzIiwiYXF1YW1hcmluZTQiLCJhcXVhbWFyaW5lMyIsCiAgICAgICAgICAgImZvcmVzdGdyZWVuIiwidG9tYXRvNCIsInRvbWF0bzMiLCJkYXJrc2FsbW9uIiwic2t5Ymx1ZSIsCiAgICAgICAgICAgImNhZGV0Ymx1ZSIsInNhbmR5YnJvd24iLCJwYWxlZ29sZGVucm9kIikKY29sc21pZGN0ID0gYygiQ2hvbGFuZ2lvY3l0ZXMiID0gImJpc3F1ZTIiLCAiSGVwYXRvY3l0ZXMiID0gInRvbWF0bzMiLCAKICAgICAgICAgICAgICAiTWVzZW5jaHltYWwiID0gInNhbmR5YnJvd24iLCAicERDcyIgPSAicm95YWxibHVlMyIsIAogICAgICAgICAgICAgICJUIGNlbGxzIiA9ICJsaWdodHNreWJsdWUzIiwgIkxTRUMiID0gImFxdWFtYXJpbmUzIiwKICAgICAgICAgICAgICAib3RoZXIgRUNzIiA9ICJmb3Jlc3RncmVlbiIsICJCIGNlbGxzIiA9ICJkYXJrb3JjaGlkMSIsCiAgICAgICAgICAgICAgIkt1cGZmZXIgY2VsbHMiID0gInNreWJsdWUxIiwgIm90aGVyIE1vbm8tTWFjIiA9ICJzdGVlbGJsdWUzIiwgCiAgICAgICAgICAgICAgIklMQyIgPSAic2xhdGVibHVlMSIpCmBgYAoKCgojIEZpZ3VyZSAxCiMjIE1haW4gRmlndXJlClVNQVAgd2l0aCBhbGwgY2VsbCB0eXBlcwoKYGBge3J9CmhjZWxsc19jc3MgPSByZWFkUkRTKCJkYXRhL3Byb2Nlc3NlZC9oY2VsbHNfY3NzLlJEUyIpCmFsbGNlbGxzX2NzcyA9IHJlYWRSRFMoZmlsZSA9ICJkYXRhL3Byb2Nlc3NlZC9hbGxjZWxsc19jc3NfcmVhbm5vdC5SRFMiKQpgYGAKCmBgYHtyLCBmaWcuaGVpZ2h0PTIsIGZpZy53aWR0aD0zfQpwbG90X2RmID0gZGF0YS5mcmFtZShoY2VsbHNfY3NzQHJlZHVjdGlvbnMkdW1hcF9jc3NAY2VsbC5lbWJlZGRpbmdzKQpwbG90X2RmJG5hbWVzX21ham9yID0gYXMuY2hhcmFjdGVyKGhjZWxsc19jc3NAbWV0YS5kYXRhJG5hbWVzX21ham9yKQpwbG90X2RmJG5hbWVzX21ham9yW3Bsb3RfZGYkbmFtZXNfbWFqb3I9PSJUIGNlbGxzIiB8IAogICAgICAgICAgICAgICAgICAgICAgcGxvdF9kZiRuYW1lc19tYWpvcj09IkIgY2VsbHMiIHwgCiAgICAgICAgICAgICAgICAgICAgICBwbG90X2RmJG5hbWVzX21ham9yPT0iTWFjcm9waGFnZXMiIHwKICAgICAgICAgICAgICAgICAgICAgIHBsb3RfZGYkbmFtZXNfbWFqb3I9PSJEQ3MiXSA9ICJJbW11bmUiCnBsb3RfZGYkbmFtZXNfbWFqb3JbcGxvdF9kZiRuYW1lc19tYWpvcj09IlN0ZWxsYXRlIGNlbGxzIl0gPSAiTWVzZW5jaHltYWwiCnBsb3RfZGYkbmFtZXNfbWFqb3JbcGxvdF9kZiRuYW1lc19tYWpvcj09IkVuZG90aGVsaWFsIGNlbGxzIl0gPSAiRW5kb3RoZWxpYWwiCnBsdCA9IGdncGxvdChwbG90X2RmLCBhZXMoeCA9IFVNQUNTU18xLCB5ID0gVU1BQ1NTXzIsIGNvbG91ciA9IG5hbWVzX21ham9yKSkrCiAgZ2VvbV9wb2ludChzaXplID0gcG9pbnRzaXplKSsKICBndWlkZXMoY29sb3VyID0gZ3VpZGVfbGVnZW5kKG92ZXJyaWRlLmFlcyA9IGxpc3Qoc2l6ZSA9IDMpLCB0aXRsZSA9ICJDZWxsIFR5cGUiKSkrCiAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBjb2xzbWFqb3IpKwogIHRoZW1lX2NsYXNzaWMoKSsKICB0aF9nZW4rCiAgdGhlbWUoYXhpcy5saW5lID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGlja3MgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRleHQgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMCksCiAgICAgICAgYXNwZWN0LnJhdGlvID0gMSkKCnBkZigiZmlndXJlX3BhbmVscy9maWcxL3VtYXBfZnJlc2hfbWFqb3IucGRmIiwgCiAgICB1c2VEaW5nYmF0cyA9IEYsIGhlaWdodCA9IDQsIHdpZHRoID0gNSkKcHJpbnQocGx0KQpkZXYub2ZmKCkKcG5nKCJmaWd1cmVfcGFuZWxzL2ZpZzEvdW1hcF9mcmVzaF9tYWpvci5wbmciLCAKICAgIGhlaWdodD04LCB3aWR0aD04LCB1bml0PSJjbSIsIHJlcz02MDAsIGFudGlhbGlhcyA9ICJzdWJwaXhlbCIpCnByaW50KHBsdCkKZGV2Lm9mZigpCnBkZigiZmlndXJlX3BhbmVscy9maWcxL3VtYXBfZnJlc2hfbWFqb3Jfbm9MZWcucGRmIiwgCiAgICB1c2VEaW5nYmF0cyA9IEYsIGhlaWdodCA9IDQsIHdpZHRoID0gNSkKcHJpbnQocGx0K3RoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikpCmRldi5vZmYoKQpwbmcoImZpZ3VyZV9wYW5lbHMvZmlnMS91bWFwX2ZyZXNoX21ham9yX25vTGVnLnBuZyIsIAogICAgaGVpZ2h0PTgsIHdpZHRoPTgsIHVuaXQ9ImNtIiwgcmVzPTYwMCwgYW50aWFsaWFzID0gInN1YnBpeGVsIikKcHJpbnQocGx0K3RoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikpCmBgYAoKVU1BUCB3aXRoIGhlYWx0aHkgZG9ub3JzCgpgYGB7ciwgZmlnLmhlaWdodD0yLCBmaWcud2lkdGg9M30KcGxvdF9kZiA9IGRhdGEuZnJhbWUoaGNlbGxzX2Nzc0ByZWR1Y3Rpb25zJHVtYXBfY3NzQGNlbGwuZW1iZWRkaW5ncykKcGxvdF9kZiREb25vciA9IGZhY3RvcihoY2VsbHNfY3NzQG1ldGEuZGF0YSREb25vcikKcGxvdF9kZiREb25vciA9IHBseXI6OnJldmFsdWUocGxvdF9kZiREb25vciwgYygiSEQxIiA9ICJzY19IMSIsICJIRDIiID0gInNjX0gyIiwgIkhEMyIgPSAic2NfSDMiKSkKCnBsdCA9IGdncGxvdChwbG90X2RmW3NhbXBsZSgxOm5yb3cocGxvdF9kZiksIG5yb3cocGxvdF9kZiksIHJlcGxhY2UgPSBGKSxdLCAKICAgICAgICAgICAgIGFlcyh4ID0gVU1BQ1NTXzEsIHkgPSBVTUFDU1NfMiwgY29sb3VyID0gRG9ub3IpKSsKICBnZW9tX3BvaW50KHNpemUgPSBwb2ludHNpemUpKwogIGd1aWRlcyhjb2xvdXIgPSBndWlkZV9sZWdlbmQob3ZlcnJpZGUuYWVzID0gbGlzdChzaXplID0gMyksIHRpdGxlID0gIkRvbm9ycyIpKSsKICBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcyA9IGNvbGRvbikrCiAgdGhlbWVfY2xhc3NpYygpKwogIHRoX2dlbisKICB0aGVtZShheGlzLmxpbmUgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy50aWNrcyA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRpdGxlID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGV4dCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwKSwKICAgICAgICBhc3BlY3QucmF0aW8gPSAxKQoKcGRmKCJmaWd1cmVfcGFuZWxzL2ZpZzEvdW1hcF9mcmVzaF9kb25vcnMucGRmIiwgCiAgICB1c2VEaW5nYmF0cyA9IEYsIGhlaWdodCA9IDQsIHdpZHRoID0gNSkKcHJpbnQocGx0KQpkZXYub2ZmKCkKcG5nKCJmaWd1cmVfcGFuZWxzL2ZpZzEvdW1hcF9mcmVzaF9kb25vcnMucG5nIiwgCiAgICBoZWlnaHQ9OCwgd2lkdGg9OCwgdW5pdD0iY20iLCByZXM9NjAwLCBhbnRpYWxpYXMgPSAic3VicGl4ZWwiKQpwcmludChwbHQpCmRldi5vZmYoKQpwZGYoImZpZ3VyZV9wYW5lbHMvZmlnMS91bWFwX2ZyZXNoX2Rvbm9yc19ub0xlZy5wZGYiLCAKICAgIHVzZURpbmdiYXRzID0gRiwgaGVpZ2h0ID0gNCwgd2lkdGggPSA1KQpwcmludChwbHQrdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKSkKZGV2Lm9mZigpCnBuZygiZmlndXJlX3BhbmVscy9maWcxL3VtYXBfZnJlc2hfZG9ub3JzX25vTGVnLnBuZyIsIAogICAgaGVpZ2h0PTgsIHdpZHRoPTgsIHVuaXQ9ImNtIiwgcmVzPTYwMCwgYW50aWFsaWFzID0gInN1YnBpeGVsIikKcHJpbnQocGx0K3RoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikpCmRldi5vZmYoKQpgYGAKClZpb2xpbnMgZm9yIGNlbGwgdHlwZSBtYXJrZXJzCgpgYGB7cn0KbWFya2VycyA9IGMoIkFTR1IxIiwgIkFQT0IiLCAiQVBPQzMiLAogICAgICAgICAgICAiS1JUNyIsIkNMRE40IiwiRVBDQU0iLAogICAgICAgICAgICAiQ0xFQzRHIiwiUEVDQU0xIiwiQ0QzNiIsCiAgICAgICAgICAgICJEQ04iLCJDT0xFQzExIiwiQUNUQTIiLAogICAgICAgICAgICAiUFRQUkMiLCJITEEtRFFBMSIsIkxZWiIpCmBgYAoKYGBge3IsIGZpZy53aWR0aD0zLjQsIGZpZy5oZWlnaHQ9NC42fQpleHBfbWsgPSBkYXRhLmZyYW1lKE1hdHJpeDo6dChoY2VsbHNfY3NzQGFzc2F5cyRTQ1RAZGF0YVttYXJrZXJzLF0pKQpwbG90X2RmID0gY2JpbmQoZXhwX21rLCAKICAgICAgICAgICAgICAgIGRhdGEuZnJhbWUobmFtZXNfbWFqb3IgPSBhcy5jaGFyYWN0ZXIoaGNlbGxzX2Nzc0BtZXRhLmRhdGFbLGMoIm5hbWVzX21ham9yIildKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHN0cmluZ3NBc0ZhY3RvcnMgPSBGKSkKcGxvdF9kZiRuYW1lc19tYWpvcltwbG90X2RmJG5hbWVzX21ham9yPT0iVCBjZWxscyIgfCAKICAgICAgICAgICAgICAgICAgICAgIHBsb3RfZGYkbmFtZXNfbWFqb3I9PSJCIGNlbGxzIiB8IAogICAgICAgICAgICAgICAgICAgICAgcGxvdF9kZiRuYW1lc19tYWpvcj09Ik1hY3JvcGhhZ2VzIiB8IAogICAgICAgICAgICAgICAgICAgICAgcGxvdF9kZiRuYW1lc19tYWpvcj09IkRDcyJdID0gIkltbXVuZSIKcGxvdF9kZiRuYW1lc19tYWpvcltwbG90X2RmJG5hbWVzX21ham9yPT0iRW5kb3RoZWxpYWwgY2VsbHMiXSA9ICJFbmRvdGhlbGlhbCIKcGxvdF9kZiRuYW1lc19tYWpvcltwbG90X2RmJG5hbWVzX21ham9yPT0iU3RlbGxhdGUgY2VsbHMiXSA9ICJNZXNlbmNoeW1hbCIKcGxvdF9kZiA9IHBsb3RfZGZbcGxvdF9kZiRuYW1lc19tYWpvciE9IkRvdWJsZXRzIixdCnBsb3RfZGYkbmFtZXNfbWFqb3IgPSBmYWN0b3IocGxvdF9kZiRuYW1lc19tYWpvciwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGV2ZWxzID0gYygiSGVwYXRvY3l0ZXMiLCAiQ2hvbGFuZ2lvY3l0ZXMiLCAiRW5kb3RoZWxpYWwiLCAiTWVzZW5jaHltYWwiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkltbXVuZSIpKQpwbG90X2RmID0gcmVzaGFwZTI6Om1lbHQocGxvdF9kZikKcGxvdF9kZiR2YXJpYWJsZSA9IGZhY3Rvcihnc3ViKCIuIiwgIi0iLCBwbG90X2RmJHZhcmlhYmxlLCBmaXhlZCA9IFQpLCBsZXZlbHMgPSBtYXJrZXJzKQoKdmlvX21rID0gZ2dwbG90KHBsb3RfZGYsIGFlcyh4ID0gbmFtZXNfbWFqb3IsIHkgPSB2YWx1ZSwgZmlsbCA9IG5hbWVzX21ham9yKSkrCiAgZmFjZXRfZ3JpZCh2YXJpYWJsZX5uYW1lc19tYWpvciwgc2NhbGVzID0gImZyZWUiKSsKICBnZW9tX3Zpb2xpbihzY2FsZSA9ICJ3aWR0aCIsIHNpemUgPSAwLjMpKwogIHNjYWxlX3lfY29udGludW91cyhicmVha3MgPSBzZXEoMCwxMCwyKSwgbGFiZWxzID0gc2VxKDAsMTAsMiksIG5hbWUgPSAibG9nKGV4cCsxKSIpKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGNvbHNtYWpvcikrCiAgdGhlbWUoc3RyaXAuYmFja2dyb3VuZC55ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIHN0cmlwLmJhY2tncm91bmQueCA9IGVsZW1lbnRfcmVjdChmaWxsID0gInRyYW5zcGFyZW50IiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG91ciA9ICJibGFjayIsIHNpemUgPSAwLjgpLAogICAgICAgIHN0cmlwLnRleHQueSA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDAsIHNpemUgPSA2LjUsIGNvbG91ciA9ICJibGFjayIsIGZhY2UgPSAiYm9sZCIpLAogICAgICAgIHN0cmlwLnRleHQueCA9IGVsZW1lbnRfdGV4dChmYWNlID0gImJvbGQiLCBzaXplID0gNi41LCBjb2xvdXIgPSAiYmxhY2siKSwKICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAibm9uZSIsCiAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF9ibGFuaygpLCAKICAgICAgICBheGlzLmxpbmUueC5ib3R0b20gPSBlbGVtZW50X2JsYW5rKCkpCgpwZGYoImZpZ3VyZV9wYW5lbHMvZmlnMS92aW9saW5fbWFya2Vyc19tYWpvci5wZGYiLCAKICAgIHVzZURpbmdiYXRzID0gRiwgaGVpZ2h0ID0gNSwgd2lkdGggPSA1LjUpCnByaW50KHZpb19taykKZGV2Lm9mZigpCnBuZygiZmlndXJlX3BhbmVscy9maWcxL3Zpb2xpbl9tYXJrZXJzX21ham9yLnBuZyIsIGhlaWdodCA9IDQyNSwgd2lkdGggPSA0NTAsIGFudGlhbGlhcyA9ICJzdWJwaXhlbCIpCnByaW50KHZpb19taykKZGV2Lm9mZigpCmBgYAoKSGVhdG1hcCBmb3IgbWFqb3IgY2VsbCB0eXBlcwoKYGBge3J9CiMgcmVtb3ZlZCBISElQCm5tZz1jKCJQREdGUkEiLCJDQUxEMSIsIkNPTDZBMSIsIlBER0ZSQiIsCiAgICAgICJDU0YxUiIsIkNEMTYzIiwiTUFSQ08iLCJDRDY5IiwiSUw3UiIsIlBDSzEiLCJDWVAyQTciLCJDWVAzQTQiLCJDUlAiLAogICAgICAiUk9CTzQiLCJFR0ZMNyIsIkNMRUM0TSIsIkZDTjIiLCJLUlQ3IiwiQ0ZUUiIsIk9ORUNVVDEiKQpwbG90X2RmID0gZGF0YS5mcmFtZShyb3cubmFtZXMgPSByb3duYW1lcyhoY2VsbHNfY3NzQG1ldGEuZGF0YSksCiAgICAgICAgICAgICAgICAgICAgIG5hbWVzX21ham9yID0gYXMuY2hhcmFjdGVyKGhjZWxsc19jc3NAbWV0YS5kYXRhWyxjKCJuYW1lc19tYWpvciIpXSksCiAgICAgICAgICAgICAgICAgICAgIGRvbm9yID0gYXMuY2hhcmFjdGVyKGhjZWxsc19jc3NAbWV0YS5kYXRhWyxjKCJEb25vciIpXSksCiAgICAgICAgICAgICAgICAgICAgIHN0cmluZ3NBc0ZhY3RvcnMgPSBGKSAKcGxvdF9kZiRuYW1lc19tYWpvcltwbG90X2RmJG5hbWVzX21ham9yPT0iVCBjZWxscyIgfCAKICAgICAgICAgICAgICAgICAgICAgIHBsb3RfZGYkbmFtZXNfbWFqb3I9PSJCIGNlbGxzIiB8IAogICAgICAgICAgICAgICAgICAgICAgcGxvdF9kZiRuYW1lc19tYWpvcj09Ik1hY3JvcGhhZ2VzIiB8IAogICAgICAgICAgICAgICAgICAgICAgcGxvdF9kZiRuYW1lc19tYWpvcj09IkRDcyJdID0gIkltbXVuZSIKcGxvdF9kZiRuYW1lc19tYWpvcltwbG90X2RmJG5hbWVzX21ham9yPT0iRW5kb3RoZWxpYWwgY2VsbHMiXSA9ICJFbmRvdGhlbGlhbCIKcGxvdF9kZiRuYW1lc19tYWpvcltwbG90X2RmJG5hbWVzX21ham9yPT0iU3RlbGxhdGUgY2VsbHMiXSA9ICJNZXNlbmNoeW1hbCIKcGxvdF9kZiA9IHBsb3RfZGZbcGxvdF9kZiRuYW1lc19tYWpvciE9IkRvdWJsZXRzIixdCnBsb3RfZGYgPSBwbG90X2RmW29yZGVyKHBsb3RfZGYkbmFtZXNfbWFqb3IpLF0KbTE9R2V0QXNzYXlEYXRhKGhjZWxsc19jc3MsIHNsb3Q9ImRhdGEiKVtubWcscm93bmFtZXMocGxvdF9kZildCm0xID0gdChhcHBseShtMSwgMSwgc2NhbGUsIHNjYWxlID0gRikpCmNvbG5hbWVzKG0xKT1yZXAoIiIsbmNvbChtMSkpCmNvdWwgPC0gY29sb3JSYW1wUGFsZXR0ZShicmV3ZXIucGFsKDksICJHcmV5cyIpKSgxMDApWy1jKDE6NSldCm0xW20xPjFdID0gMQojbTFbbTE8PSgtMildID0gLTIKaGVhdG1hcChtMSxSb3d2ID0gTkEsQ29sdiA9IE5BLCBjb2w9Y291bCkKYGBgCgpWaW9saW5zIGZvciBhbGwgY2VsbCB0eXBlcwoKYGBge3IsIGZpZy53aWR0aD0zLjQsIGZpZy5oZWlnaHQ9NC42fQpleHBfbWsgPSBkYXRhLmZyYW1lKE1hdHJpeDo6dChoY2VsbHNfY3NzQGFzc2F5cyRTQ1RAZGF0YVttYXJrZXJzLF0pKQpwbG90X2RmID0gY2JpbmQoZXhwX21rLCAKICAgICAgICAgICAgICAgIGhjZWxsc19jc3NAbWV0YS5kYXRhWyxjKCJuYW1lc19tYWpvciIsIm5hbWVzX2NsdXN0ZXJzIildKQpwbG90X2RmJG5hbWVzX21ham9yID0gYXMuY2hhcmFjdGVyKHBsb3RfZGYkbmFtZXNfbWFqb3IpCnBsb3RfZGYkbmFtZXNfbWFqb3JbcGxvdF9kZiRuYW1lc19tYWpvcj09IlQgY2VsbHMiIHwgCiAgICAgICAgICAgICAgICAgICAgICBwbG90X2RmJG5hbWVzX21ham9yPT0iQiBjZWxscyIgfCAKICAgICAgICAgICAgICAgICAgICAgIHBsb3RfZGYkbmFtZXNfbWFqb3I9PSJNYWNyb3BoYWdlcyIgfCAKICAgICAgICAgICAgICAgICAgICAgIHBsb3RfZGYkbmFtZXNfbWFqb3I9PSJEQ3MiXSA9ICJJbW11bmUiCnBsb3RfZGYkbmFtZXNfbWFqb3JbcGxvdF9kZiRuYW1lc19tYWpvcj09IkVuZG90aGVsaWFsIGNlbGxzIl0gPSAiRW5kb3RoZWxpYWwiCnBsb3RfZGYkbmFtZXNfbWFqb3JbcGxvdF9kZiRuYW1lc19tYWpvcj09IlN0ZWxsYXRlIGNlbGxzIl0gPSAiTWVzZW5jaHltYWwiCnBsb3RfZGYgPSBwbG90X2RmW3Bsb3RfZGYkbmFtZXNfbWFqb3IhPSJEb3VibGV0cyIsXQpwbG90X2RmJG5hbWVzX21ham9yID0gZmFjdG9yKHBsb3RfZGYkbmFtZXNfbWFqb3IsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxldmVscyA9IGMoIkhlcGF0b2N5dGVzIiwgIkNob2xhbmdpb2N5dGVzIiwgIkVuZG90aGVsaWFsIiwgIk1lc2VuY2h5bWFsIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJJbW11bmUiKSkKcGxvdF9kZiA9IHJlc2hhcGUyOjptZWx0KHBsb3RfZGYpCnBsb3RfZGYkdmFyaWFibGUgPSBmYWN0b3IoZ3N1YigiLiIsICItIiwgcGxvdF9kZiR2YXJpYWJsZSwgZml4ZWQgPSBUKSwgbGV2ZWxzID0gbWFya2VycykKCmdncGxvdChwbG90X2RmLCBhZXMoeCA9IG5hbWVzX2NsdXN0ZXJzLCB5ID0gdmFsdWUsIGZpbGwgPSBuYW1lc19jbHVzdGVycykpKwogIGZhY2V0X2dyaWQodmFyaWFibGV+bmFtZXNfbWFqb3IsIHNjYWxlcyA9ICJmcmVlIikrCiAgZ2VvbV92aW9saW4oc2NhbGUgPSAid2lkdGgiKSsKICBzY2FsZV95X2NvbnRpbnVvdXMoYnJlYWtzID0gc2VxKDAsMTAsMiksIGxhYmVscyA9IHNlcSgwLDEwLDIpLCBuYW1lID0gImxvZyhleHArMSkiKSsKICAjc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gY29sc21ham9yKSsKICB0aGVtZShzdHJpcC5iYWNrZ3JvdW5kLnkgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgc3RyaXAuYmFja2dyb3VuZC54ID0gZWxlbWVudF9yZWN0KGZpbGwgPSAidHJhbnNwYXJlbnQiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3VyID0gImJsYWNrIiwgc2l6ZSA9IDAuOCksCiAgICAgICAgc3RyaXAudGV4dC55ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gMCwgc2l6ZSA9IDYuNSwgY29sb3VyID0gImJsYWNrIiwgZmFjZSA9ICJib2xkIiksCiAgICAgICAgc3RyaXAudGV4dC54ID0gZWxlbWVudF90ZXh0KGZhY2UgPSAiYm9sZCIsIHNpemUgPSA2LjUsIGNvbG91ciA9ICJibGFjayIpLAogICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwKICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IC0zNSwgaGp1c3QgPSAwLCB2anVzdCA9IDAuMSksCiAgICAgICAgYXhpcy5saW5lLnguYm90dG9tID0gZWxlbWVudF9ibGFuaygpKQpgYGAKCkNlbGwgdHlwZSBwcm9wb3J0aW9ucwoKYGBge3J9CnBsb3RfZGYgPSBkYXRhLmZyYW1lKCJuYW1lc19tYWpvciIgPSBhcy5jaGFyYWN0ZXIoaGNlbGxzX2Nzc0BtZXRhLmRhdGEkbmFtZXNfbWFqb3IpLAogICAgICAgICAgICAgICAgICAgICAiRG9ub3IiID0gYXMuY2hhcmFjdGVyKGhjZWxsc19jc3NAbWV0YS5kYXRhJERvbm9yKSwKICAgICAgICAgICAgICAgICAgICAgc3RyaW5nc0FzRmFjdG9ycyA9IEYpCnBsb3RfZGYkbmFtZXNfbWFqb3JbcGxvdF9kZiRuYW1lc19tYWpvcj09IlQgY2VsbHMiIHwgCiAgICAgICAgICAgICAgICAgICAgICBwbG90X2RmJG5hbWVzX21ham9yPT0iQiBjZWxscyIgfCAKICAgICAgICAgICAgICAgICAgICAgIHBsb3RfZGYkbmFtZXNfbWFqb3I9PSJNYWNyb3BoYWdlcyIgfCAKICAgICAgICAgICAgICAgICAgICAgIHBsb3RfZGYkbmFtZXNfbWFqb3I9PSJEQ3MiXSA9ICJJbW11bmUiCnBsb3RfZGYkbmFtZXNfbWFqb3JbcGxvdF9kZiRuYW1lc19tYWpvcj09IkVuZG90aGVsaWFsIGNlbGxzIl0gPSAiRW5kb3RoZWxpYWwiCnBsb3RfZGYkbmFtZXNfbWFqb3JbcGxvdF9kZiRuYW1lc19tYWpvcj09IlN0ZWxsYXRlIGNlbGxzIl0gPSAiTWVzZW5jaHltYWwiCnBsb3RfZGYgPSBwbG90X2RmW3Bsb3RfZGYkbmFtZXNfbWFqb3IhPSJEb3VibGV0cyIsXQpjbnRzX2N0ID0gdGFibGUocGxvdF9kZiRuYW1lc19tYWpvciwgcGxvdF9kZiREb25vcikKcGxvdF9kZiA9IHJlc2hhcGUyOjptZWx0KGFwcGx5KGNudHNfY3QsIDEsIGZ1bmN0aW9uKHgpIHgvc3VtKHgpKSkKI3Bsb3RfZGYkVmFyMiA9IGZhY3RvcihwbG90X2RmJFZhcjIsIAojICAgICAgICAgICAgICAgICAgICAgIGxldmVscyA9IGMoIkhlcGF0b2N5dGVzIiwgIkNob2xhbmdpb2N5dGVzIiwgIkVuZG90aGVsaWFsIiwiTWVzZW5jaHltYWwiLCAiSW1tdW5lIikpCnBsb3RfZGYkVmFyMSA9IHBseXI6OnJldmFsdWUocGxvdF9kZiRWYXIxLCBjKCJIRDEiID0gInNjX0gxIiwgIkhEMiIgPSAic2NfSDIiLCAiSEQzIiA9ICJzY19IMyIpKQpwbG90X2RmJFZhcjEgPSBmYWN0b3IocGxvdF9kZiRWYXIxLCBsZXZlbHMgPSByZXYobGV2ZWxzKHBsb3RfZGYkVmFyMSkpKQoKcGx0ID0gZ2dwbG90KHBsb3RfZGYsIGFlcyh4ID0gVmFyMiwgeSA9IHZhbHVlKjEwMCwgZmlsbCA9IFZhcjEpKSsKICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IikrCiAgc2NhbGVfeV9jb250aW51b3VzKGV4cGFuZCA9IGMoMCwwKSkrCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gY29sZG9uKSsKICBsYWJzKHkgPSAiQ2VsbCB0eXBlIHByb3BvcnRpb24gWyVdIiwgeCA9IE5VTEwpKwogIHRoZW1lX2NsYXNzaWMoKSsKICB0aF9nZW4rCiAgdGhlbWUoYXhpcy5saW5lLnggPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy50aWNrcy55ID0gZWxlbWVudF9saW5lKCksCiAgICAgICAgYXhpcy50aWNrcy54ID0gZWxlbWVudF9ibGFuaygpKQoKcGRmKCJmaWd1cmVfcGFuZWxzL2ZpZzEvcHJvcG9ydGlvbnNfZnJlc2hfbWFqb3JfZG9ub3IucGRmIiwgCiAgICB1c2VEaW5nYmF0cyA9IEYsIGhlaWdodCA9IDQsIHdpZHRoID0gNSkKcHJpbnQocGx0KQpkZXYub2ZmKCkKcG5nKCJmaWd1cmVfcGFuZWxzL2ZpZzEvcHJvcG9ydGlvbnNfZnJlc2hfbWFqb3JfZG9ub3IucG5nIiwgCiAgICBoZWlnaHQgPSAzMjUsIHdpZHRoID0gNDAwLCBhbnRpYWxpYXMgPSAic3VicGl4ZWwiKQpwcmludChwbHQpCmRldi5vZmYoKQpwZGYoImZpZ3VyZV9wYW5lbHMvZmlnMS9wcm9wb3J0aW9uc19mcmVzaF9tYWpvcl9kb25vcl9ub0xlZy5wZGYiLCAKICAgIHVzZURpbmdiYXRzID0gRiwgaGVpZ2h0ID0gNCwgd2lkdGggPSA1KQpwcmludChwbHQrdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKSkKZGV2Lm9mZigpCnBuZygiZmlndXJlX3BhbmVscy9maWcxL3Byb3BvcnRpb25zX2ZyZXNoX21ham9yX2Rvbm9yX25vTGVnLnBuZyIsIAogICAgaGVpZ2h0ID0gMzI1LCB3aWR0aCA9IDQwMCwgYW50aWFsaWFzID0gInN1YnBpeGVsIikKcHJpbnQocGx0K3RoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikpCmRldi5vZmYoKQpgYGAKCkltcG9ydCBtYXJrZXJzCgpgYGB7cn0KbWFya2VycyA9IGMoIkFTR1IxIiwgIkFQT0IiLCAiQVBPQzMiLCAiQ1lQMkUxIiwgIkhBTVAiLCAiT1JNMSIsICJTQUExIiwgIk5OTVQiLCAiRkFCUDEiLCAiTVQxRyIsICJPUk0yIiwgIlRUUiIsICJIUCIsICJBUE9DMSIsICJBUE9BMiIsIkZHQiIsIkNZUDNBNCIsIkNQUzEiLCJBUkcxIiwiU0FBMiIsIyBIZXAKICAgICAgICAgICAgIktSVDciLCJDTERONCIsIkVQQ0FNIiwgIlRBQ1NURDIiLCAiQ0QyNCIsICJLUlQxOSIsICJBTlhBNCIsICJDWENMNiIsICJGWFlEMiIsICJTT1g0IiwgICJDUllBQiIsIkRFRkIxIiwiU0xDMTJBMiIsIk1NUDciLCJUTkZSU0YxMkEiLCJDWENMMSIsIkJJQ0MxIiwiUzEwMEExNCIsIkRDREMyIiwiUExQUDIiLCMgQ2hvCiAgICAgICAgICAgICJDTEVDNEciLCJQRUNBTTEiLCJDRDM2IiwgIkZDTjMiLCAiRE5BU0UxTDMiLCAiQ0xFQzFCIiwgIkNSSEJQIiwgIkFLQVAxMiIsICJJRkkyNyIsICJHTkcxMSIsICJJTDMzIiwiRkxUMSIsIlBSU1MyMyIsIkVORyIsIlJBTVAzIiwiRjgiLCJWV0YiLCJDTERONSIsIkNDTDE0IiwiTFlWRTEiLCMgRW5kCiAgICAgICAgICAgICJEQ04iLCJDT0xFQzExIiwiQUNUQTIiLCAiQ0NMMiIsICJUQUdMTiIsICJJR0ZCUDMiLCAiQkdOIiwgIkxVTSIsICJDT0wzQTEiLCAiTVlMOSIsICJUUE0yIiwiQUVCUDEiLCJHR1Q1IiwiQVNQTiIsIkNPTDE0QTEiLCJQVEdEUyIsIkNPTDZBMSIsIkNZUjYxIiwiQ09MRUMxMCIsIkNYQ0wxMiIsIyBNZXMKICAgICAgICAgICAgIlBUUFJDIiwiSExBLURRQTEiLCJMWVoiLCAiTElMUkIyIiwgIk1BUkNPIiwgIkMxUUIiLCAiRkNHUjNBIiwgICJOS0c3IiwgIk1TNEExIiwgIk1aQjEiLCAiQ0NMNSIsIktMUkQxIiwiQVJFRyIsIk1TNEE3IiwiQVhMIiwiQ0Q2OSIsIkdQUjE4MyIsIlRMUjIiLCJDRDQ0IiwiSUw3UiIpICMgSW1tCm1rX2xpc3QgPSBsaXN0KCJIZXBhdG9jeXRlcyIgPSBtYXJrZXJzWzE6MTBdLCAiQ2hvbGFuZ2lvY3l0ZXMiID0gbWFya2Vyc1syMTozMF0sIAogICAgICAgICAgICAgICAiRW5kb3RoZWxpYWwiID0gbWFya2Vyc1s0MTo1MF0sICJNZXNlbmNoeW1hbCIgPSBtYXJrZXJzWzYxOjcwXSwgIkltbXVuZSIgPSBtYXJrZXJzWzgxOjkwXSkKCmNlbGxfdHlwZV9tayA9IHJlYWRSRFMoZmlsZSA9ICJyZXN1bHRzL2ludGVncl9hbGxjZWxscy9jZWxsX3R5cGVfbWtfbWFqb3IuUkRTIikKZnJlc2hfZGUgPSBsaXN0KCkKZm9yKG4gaW4gdW5pcXVlKGNlbGxfdHlwZV9tayRtYWpvcl9hbGwkY2x1c3RlcikpewogIGZyZXNoX2RlW1tuXV0gPSBjZWxsX3R5cGVfbWskbWFqb3JfYWxsW2NlbGxfdHlwZV9tayRtYWpvcl9hbGwkY2x1c3Rlcj09bixdCn0KCmxvYWQoImRhdGEvcHJvY2Vzc2VkL3JlY2VpdmVkX0FnYS9ERV90YWJsZXNfY2VsbHR5cGVfZnJvemVuU0NULnJkYXRhIikKZnJvemVuX2RlID0gbGlzdCgiQ2hvbGFuZ2lvY3l0ZXMiID0gY2VsbF90eXBlX21rX2NobywgIkhlcGF0b2N5dGVzIiA9IGNlbGxfdHlwZV9ta19oZXAsIAogICAgICAgICAgICAgICAgICJFbmRvdGhlbGlhbCIgPSBjZWxsX3R5cGVfbWtfZWMsICJJbW11bmUiID0gY2VsbF90eXBlX21rX2ltbSwgCiAgICAgICAgICAgICAgICAgIk1lc2VuY2h5bWFsIiA9IGNlbGxfdHlwZV9ta19tZXMpCmZvcihuIGluIG5hbWVzKGZyb3plbl9kZSkpewogIGZyb3plbl9kZVtbbl1dJGNsdXN0ZXIgPSBuCiAgZnJvemVuX2RlW1tuXV0kZ2VuZSA9IHJvd25hbWVzKGZyb3plbl9kZVtbbl1dKQp9Cgpib3RoX2xpc3QgPSBsaXN0KCkKdG9wX21rID0gbGlzdCgpCmZvcihuIGluIG5hbWVzKGZyZXNoX2RlKSl7CiAgYm90aF9ERSA9IG1lcmdlKGZyZXNoX2RlW1tuXV0sIGZyb3plbl9kZVtbbl1dLCBieSA9ICJnZW5lIiwgYWxsID0gVClbLGMoMSwzLDYsOSwxMildCiAgY29sbmFtZXMoYm90aF9ERSkgPSBjKCJnZW5lIiwgIkZDX2ZyZXNoIiwgInB2YWxfZnJlc2giLCAiRkNfZnJvemVuIiwgInB2YWxfZnJvemVuIikKICBib3RoX0RFJEZDX2ZyZXNoW2lzLm5hKGJvdGhfREUkRkNfZnJlc2gpXSA9IDAKICBib3RoX0RFJHB2YWxfZnJlc2hbaXMubmEoYm90aF9ERSRwdmFsX2ZyZXNoKV0gPSAxCiAgYm90aF9ERSRGQ19mcm96ZW5baXMubmEoYm90aF9ERSRGQ19mcm96ZW4pXSA9IDAKICBib3RoX0RFJHB2YWxfZnJvemVuW2lzLm5hKGJvdGhfREUkcHZhbF9mcm96ZW4pXSA9IDEKICBib3RoX0RFJGNlbGx0eXBlID0gbgogIGJvdGhfREUkcyA9IGJvdGhfREUkRkNfZnJlc2grYm90aF9ERSRGQ19mcm96ZW4KICBib3RoX0RFID0gYm90aF9ERVtvcmRlcihib3RoX0RFJHMsIGRlY3JlYXNpbmcgPSBUKSxdCiAgY29uZF9mYyA9IGJvdGhfREUkRkNfZnJlc2g+PTAuMSAmIGJvdGhfREUkRkNfZnJvemVuPj0wLjEKICBjb25kX3B2ID0gYm90aF9ERSRwdmFsX2ZyZXNoPD0wLjA1IHwgYm90aF9ERSRwdmFsX2Zyb3plbjw9MC4wNQogIGJvdGhfREUkaXNjb2wgPSBpZmVsc2UoY29uZF9mYyAmIGNvbmRfcHYsIAogICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKGJvdGhfREUkZ2VuZSAlaW4lIG1rX2xpc3RbW25dXSwgImlzdG9wIiwgImlzREUiKSwgIm5vdERFIikKICBib3RoX0RFJGlzY29sID0gZmFjdG9yKGJvdGhfREUkaXNjb2wsIGxldmVscyA9IHJldihjKCJpc3RvcCIsICJpc0RFIiwgIm5vdERFIikpKQogIGJvdGhfREUkaXN0b3AgPSBib3RoX0RFJGdlbmUgJWluJSBta19saXN0W1tuXV0jWzE6M10KICBib3RoX2xpc3RbW25dXSA9IGJvdGhfREUKICB0b3BfbWtbW25dXSA9IGJvdGhfREUkZ2VuZVtjb25kX2ZjICYgY29uZF9wdl1bMToyMF0KfQp0b3BfbWsgPSB0b3BfbWtbYyg0LDEsMyw1LDIpXQpgYGAKCkhlYXRtYXAgcGVyIGNsdXN0ZXIKCmBgYHtyfQpjZWxsX3R5cGVfbWsgPSByZWFkUkRTKGZpbGUgPSAicmVzdWx0cy9jb25kX2VmZmVjdC9jZWxsX3R5cGVfbWsuUkRTIikKIyBjdXQgbWFya2VycyBoZXJlIGRlcGVuZGluZyBvbiB0aGUgc2l6ZSB5b3Ugd2FudCBmb3IgaGVhdG1hcCwgdGhlbiBhZGp1c3QgZmlndXJlCm1hcmtlcnMgPSBjKCJBU0dSMSIsICJBUE9CIiwgIkFQT0MzIiwgIkNZUDJFMSIsICJIQU1QIiwgIk9STTEiLCAiU0FBMSIsICJOTk1UIiwgIkZBQlAxIiwgIk1UMUciLCAiT1JNMiIsICJUVFIiLCAiSFAiLCAiQVBPQzEiLCAiQVBPQTIiLCJGR0IiLCJDWVAzQTQiLCJDUFMxIiwiQVJHMSIsIlNBQTIiLCMgSGVwCiAgICAgICAgICAgICJLUlQ3IiwiQ0xETjQiLCJFUENBTSIsICJUQUNTVEQyIiwgIkNEMjQiLCAiS1JUMTkiLCAiQU5YQTQiLCAiQ1hDTDYiLCAiRlhZRDIiLCAiU09YNCIsICAiQ1JZQUIiLCJERUZCMSIsIlNMQzEyQTIiLCJNTVA3IiwiVE5GUlNGMTJBIiwiQ1hDTDEiLCJCSUNDMSIsIlMxMDBBMTQiLCJEQ0RDMiIsIlBMUFAyIiwjIENobwogICAgICAgICAgICAiQ0xFQzRHIiwiUEVDQU0xIiwiQ0QzNiIsICJGQ04zIiwgIkROQVNFMUwzIiwgIkNMRUMxQiIsICJDUkhCUCIsICJBS0FQMTIiLCAiSUZJMjciLCAiR05HMTEiLCAiSUwzMyIsIkZMVDEiLCJQUlNTMjMiLCJFTkciLCJSQU1QMyIsIkY4IiwiVldGIiwiQ0xETjUiLCJDQ0wxNCIsIkxZVkUxIiwjIEVuZAogICAgICAgICAgICAiRENOIiwiQ09MRUMxMSIsIkFDVEEyIiwgIkNDTDIiLCAiVEFHTE4iLCAiSUdGQlAzIiwgIkJHTiIsICJMVU0iLCAiQ09MM0ExIiwgIk1ZTDkiLCAiVFBNMiIsIkFFQlAxIiwiR0dUNSIsIkFTUE4iLCJDT0wxNEExIiwiUFRHRFMiLCJDT0w2QTEiLCJDWVI2MSIsIkNPTEVDMTAiLCJDWENMMTIiLCMgTWVzCiAgICAgICAgICAgICJQVFBSQyIsIkhMQS1EUUExIiwiTFlaIiwgIkxJTFJCMiIsICJNQVJDTyIsICJDMVFCIiwgIkZDR1IzQSIsICAiTktHNyIsICJNUzRBMSIsICJNWkIxIiwgIkNDTDUiLCJLTFJEMSIsIkFSRUciLCJNUzRBNyIsIkFYTCIsIkNENjkiLCJHUFIxODMiLCJUTFIyIiwiQ0Q0NCIsIklMN1IiKSAjIEltbQptYXJrZXJzX3RvcGJvdGggPSB1bmxpc3QodG9wX21rKQptYXJrZXJzID0gbWFya2Vyc190b3Bib3RoCgpsb2FkKCJkYXRhL3Byb2Nlc3NlZC9yZWNlaXZlZF9BZ2EvbWVhbl9leHBfY2VsbHR5cGVfZnJvemVuLnJkYXRhIikKaGNlbGxzX2Nzc0BtZXRhLmRhdGEkbWFqb3JfY3QgPSBhcy5jaGFyYWN0ZXIoaGNlbGxzX2Nzc0BtZXRhLmRhdGEkbmFtZXNfbWFqb3IpCmhjZWxsc19jc3NAbWV0YS5kYXRhJG1ham9yX2N0W2hjZWxsc19jc3NAbWV0YS5kYXRhJG1ham9yX2N0PT0iVCBjZWxscyIgfCAKICAgICAgICAgICAgICAgICAgICAgIGhjZWxsc19jc3NAbWV0YS5kYXRhJG1ham9yX2N0PT0iQiBjZWxscyIgfCAKICAgICAgICAgICAgICAgICAgICAgIGhjZWxsc19jc3NAbWV0YS5kYXRhJG1ham9yX2N0PT0iTWFjcm9waGFnZXMiIHwKICAgICAgICAgICAgICAgICAgICAgIGhjZWxsc19jc3NAbWV0YS5kYXRhJG1ham9yX2N0PT0iRENzIl0gPSAiSW1tdW5lIgpoY2VsbHNfY3NzQG1ldGEuZGF0YSRtYWpvcl9jdFtoY2VsbHNfY3NzQG1ldGEuZGF0YSRtYWpvcl9jdD09IlN0ZWxsYXRlIGNlbGxzIl0gPSAiTWVzZW5jaHltYWwiCmhjZWxsc19jc3NAbWV0YS5kYXRhJG1ham9yX2N0W2hjZWxsc19jc3NAbWV0YS5kYXRhJG1ham9yX2N0PT0iRW5kb3RoZWxpYWwgY2VsbHMiXSA9ICJFbmRvdGhlbGlhbCIKbV9jdF9mcmVzaCA9IGFwcGx5KGFzLm1hdHJpeChoY2VsbHNfY3NzQGFzc2F5cyRTQ1RAZGF0YSksIDEsIAogICAgICAgICAgICAgICAgICAgZnVuY3Rpb24oeCkgdGFwcGx5KHgsIGhjZWxsc19jc3NAbWV0YS5kYXRhJG1ham9yX2N0LCBtZWFuKSkKCm1fY3RfZnJvemVuID0gdChtX2N0X2Zyb3plbikKbV9jdF9mcm96ZW4gPSB0KGFwcGx5KG1fY3RfZnJvemVuLCAxLCBzY2FsZSkpCmNvbG5hbWVzKG1fY3RfZnJvemVuKSA9IHJvd25hbWVzKG1fY3RfZnJlc2gpWy0yXQptX2N0X2ZyZXNoID0gdChtX2N0X2ZyZXNoKVssLTJdCm1fY3RfZnJlc2ggPSB0KGFwcGx5KG1fY3RfZnJlc2gsIDEsIHNjYWxlKSkKY29sbmFtZXMobV9jdF9mcmVzaCkgPSBjb2xuYW1lcyhtX2N0X2Zyb3plbikKCm1lYW5fY3QgPSBtZXJnZShtX2N0X2ZyZXNoLCBtX2N0X2Zyb3plbiwgYnkgPSAwKQpyb3duYW1lcyhtZWFuX2N0KSA9IG1lYW5fY3RbLDFdCm1lYW5fY3QgPSBtZWFuX2N0WywtMV0KY29sbmFtZXMobWVhbl9jdCkgPSBwYXN0ZTAocmVwKGNvbG5hbWVzKG1fY3RfZnJlc2gpLCAyKSwgcmVwKGMoIl9mcmVzaCIsICJfZnJvemVuIiksIGVhY2ggPSA1KSkKCmhjbCA9IGhjbHVzdChkaXN0KHQobWVhbl9jdCkpLCBtZXRob2QgPSAid2FyZC5EMiIpCnBsb3QoaGNsKQoKYW5ub3RfZGYgPSBkYXRhLmZyYW1lKHJvdy5uYW1lcyA9IGNvbG5hbWVzKG1lYW5fY3QpLAogICAgICAgICAgICAgICAgICAgICAgImNlbGwgdHlwZSIgPSB1bmxpc3QobGFwcGx5KHN0cnNwbGl0KGNvbG5hbWVzKG1lYW5fY3QpLCAiXyIpLCBmdW5jdGlvbih4KSB4WzFdKSksCiAgICAgICAgICAgICAgICAgICAgICAicHJvY2Vzc2luZyIgPSB1bmxpc3QobGFwcGx5KHN0cnNwbGl0KGNvbG5hbWVzKG1lYW5fY3QpLCAiXyIpLCBmdW5jdGlvbih4KSB4WzJdKSkpCgpjYWxsYmFjayA9IGZ1bmN0aW9uKGhjLCBtYXQpewogIHN2ID0gc3ZkKHQobWF0KSkkdlssMl0KICAgIGRlbmQgPSByZW9yZGVyKGFzLmRlbmRyb2dyYW0oaGMpLCBjKDE6NCwpKQogICAgYXMuaGNsdXN0KGRlbmQpCn0KCnBkZigiZmlndXJlX3BhbmVscy9maWcxL21ham9yX2NlbGx0eXBlc19oZWF0bWFwX2ZyZXNoZnJvemVuXzEwLnBkZiIsIAogICAgdXNlRGluZ2JhdHMgPSBGLCBoZWlnaHQgPSA3LjUsIHdpZHRoID0gNikKaGVhdCA9IHBoZWF0bWFwOjpwaGVhdG1hcChtZWFuX2N0W21hcmtlcnNbYyg0MTo1MCwgNjE6NzAsIDgxOjkwLCAgMToxMCwgMjE6MzApXSxdLCAKICAgICAgICAgICAgICAgICAgICAgICAgICBjbHVzdGVyaW5nX21ldGhvZCA9ICJ3YXJkLkQyIiwgdHJlZWhlaWdodF9yb3cgPSAwLCBhbm5vdGF0aW9uX2NvbCA9IGFubm90X2RmLAogICAgICAgICAgICAgICAgICAgICAgICAgIGNsdXN0ZXJfcm93cyA9IEYsIHRyZWVoZWlnaHRfY29sID0gMjAsIGZvbnRzaXplX3JvdyA9IDUuNSwKICAgICAgICAgICAgICAgICAgICAgICAgICBhbm5vdGF0aW9uX2NvbG9ycyA9IGxpc3QoInByb2Nlc3NpbmciID0gYygiZnJlc2giID0gIiNkNGQ0ZDQiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiZnJvemVuIiA9ICIjNWQ1ZDVkIiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJjZWxsLnR5cGUiID0gY29sc21ham9yWy02XSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgc2hvd19jb2xuYW1lcyA9IEYsIAogICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG9yID0gY29sb3JSYW1wUGFsZXR0ZShyZXYoYnJld2VyLnBhbChuID0gOSwgbmFtZSA9ICJSZEJ1IikpKSgxMDApKQpkZXYub2ZmKCkKYGBgCgpGQyBmcmVzaCB2cyBmcm96ZW4KCmBgYHtyfQpta19saXN0ID0gbGlzdCgiSGVwYXRvY3l0ZXMiID0gbWFya2Vyc1sxOjEwXSwgIkNob2xhbmdpb2N5dGVzIiA9IG1hcmtlcnNbMjE6MzBdLCAKICAgICAgICAgICAgICAgIkVuZG90aGVsaWFsIiA9IG1hcmtlcnNbNDE6NTBdLCAiTWVzZW5jaHltYWwiID0gbWFya2Vyc1s2MTo3MF0sICJJbW11bmUiID0gbWFya2Vyc1s4MTo5MF0pCgpwbHRfZmNfbGlzdCA9IGxpc3QoKQpwZGYoImZpZ3VyZV9wYW5lbHMvZmlnMS9tYWpvcl9jZWxsdHlwZXNfRkNzY2F0dGVyXzEwLnBkZiIsIAogICAgdXNlRGluZ2JhdHMgPSBGLCBoZWlnaHQgPSA1LCB3aWR0aCA9IDQuNSkKZm9yKG4gaW4gbmFtZXMoYm90aF9saXN0KSl7CiAgYm90aF9ERSA9IGJvdGhfbGlzdFtbbl1dCiAgY2MgPSBjb3IoYm90aF9ERSRGQ19mcmVzaCwgYm90aF9ERSRGQ19mcm96ZW4pCiAgYm90aF9ERSA9IGJvdGhfREVbb3JkZXIoYm90aF9ERSRpc2NvbCksXQogIAogIGNvbHNfdXNlID0gYygiaXN0b3AiID0gdW5uYW1lKGNvbHNtYWpvcltuXSksICJpc0RFIiA9ICJncmV5MzUiLCAibm90REUiID0gImdyZXk4NSIpCiAgcGx0ID0gZ2dwbG90KGJvdGhfREUsIGFlcyh4ID0gRkNfZnJlc2gsIHkgPSBGQ19mcm96ZW4sIGNvbG91ciA9IGlzY29sKSkrCiAgICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAwLCBjb2xvdXIgPSAiZ3JleTQwIikrCiAgICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwLCBjb2xvdXIgPSAiZ3JleTQwIikrCiAgICBnZW9tX3BvaW50KCkrCiAgICBnZW9tX3RleHRfcmVwZWwoZGF0YSA9IGJvdGhfREVbYm90aF9ERSRpc3RvcCAmIGJvdGhfREUkaXNjb2w9PSJpc3RvcCIsXSwgbWFwcGluZyA9IGFlcyhsYWJlbCA9IGdlbmUpLAogICAgICAgICAgICAgICAgICAgIGZvbnRmYWNlID0gImJvbGQiKSsKICAgIHRoZW1lX2J3KCkrCiAgICBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcyA9IGNvbHNfdXNlKSsKICAgIGxhYnModGl0bGUgPSBuLCBzdWJ0aXRsZSA9IHBhc3RlMCgiUENDID0gIiwgcm91bmQoY2MsIDIpKSkrCiAgICB0aGVtZShhc3BlY3QucmF0aW8gPSAxLAogICAgICAgICAgYXhpcy50ZXh0ID0gZWxlbWVudF90ZXh0KGNvbG91ciA9ICJibGFjayIpLAogICAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLCAKICAgICAgICAgIHBhbmVsLmdyaWQgPSBlbGVtZW50X2JsYW5rKCkpCiAgCiAgcGx0X2ZjX2xpc3RbW25dXSA9IHBsdAogIHByaW50KHBsdCkKfQpkZXYub2ZmKCkKYGBgCgpFeHByZXNzaW9uIGNvbXBhcmlzb24gZnJlc2ggdnMgZnJvemVuCgpgYGB7cn0KbG9hZCgiZGF0YS9wcm9jZXNzZWQvcmVjZWl2ZWRfQWdhL21lYW5fZXhwX2NlbGx0eXBlX2Zyb3plbkNPVU5UUy5yZGF0YSIpCmhjZWxsc19jc3NAbWV0YS5kYXRhJG1ham9yX2N0ID0gYXMuY2hhcmFjdGVyKGhjZWxsc19jc3NAbWV0YS5kYXRhJG5hbWVzX21ham9yKQpoY2VsbHNfY3NzQG1ldGEuZGF0YSRtYWpvcl9jdFtoY2VsbHNfY3NzQG1ldGEuZGF0YSRtYWpvcl9jdD09IlQgY2VsbHMiIHwgCiAgICAgICAgICAgICAgICAgICAgICBoY2VsbHNfY3NzQG1ldGEuZGF0YSRtYWpvcl9jdD09IkIgY2VsbHMiIHwgCiAgICAgICAgICAgICAgICAgICAgICBoY2VsbHNfY3NzQG1ldGEuZGF0YSRtYWpvcl9jdD09Ik1hY3JvcGhhZ2VzIiB8CiAgICAgICAgICAgICAgICAgICAgICBoY2VsbHNfY3NzQG1ldGEuZGF0YSRtYWpvcl9jdD09IkRDcyJdID0gIkltbXVuZSIKaGNlbGxzX2Nzc0BtZXRhLmRhdGEkbWFqb3JfY3RbaGNlbGxzX2Nzc0BtZXRhLmRhdGEkbWFqb3JfY3Q9PSJTdGVsbGF0ZSBjZWxscyJdID0gIk1lc2VuY2h5bWFsIgpoY2VsbHNfY3NzQG1ldGEuZGF0YSRtYWpvcl9jdFtoY2VsbHNfY3NzQG1ldGEuZGF0YSRtYWpvcl9jdD09IkVuZG90aGVsaWFsIGNlbGxzIl0gPSAiRW5kb3RoZWxpYWwiCm1fY3RfZnJlc2ggPSBhcHBseShhcy5tYXRyaXgoaGNlbGxzX2Nzc0Bhc3NheXMkU0NUQGNvdW50cyksIDEsIAogICAgICAgICAgICAgICAgICAgZnVuY3Rpb24oeCkgdGFwcGx5KHgsIGhjZWxsc19jc3NAbWV0YS5kYXRhJG1ham9yX2N0LCBtZWFuKSkKCm1fY3RfZnJvemVuID0gbG9nKHQobV9jdF9mcm96ZW4uY291bnRzKSkKI21fY3RfZnJvemVuID0gdChhcHBseShtX2N0X2Zyb3plbiwgMSwgc2NhbGUpKQpjb2xuYW1lcyhtX2N0X2Zyb3plbikgPSByb3duYW1lcyhtX2N0X2ZyZXNoKVstMl0KbV9jdF9mcmVzaCA9IGxvZyh0KG1fY3RfZnJlc2gpWywtMl0pCiNtX2N0X2ZyZXNoID0gdChhcHBseShtX2N0X2ZyZXNoLCAxLCBzY2FsZSkpCmNvbG5hbWVzKG1fY3RfZnJlc2gpID0gY29sbmFtZXMobV9jdF9mcm96ZW4pCgptZWFuX2N0ID0gbWVyZ2UobV9jdF9mcmVzaCwgbV9jdF9mcm96ZW4sIGJ5ID0gMCkKcm93bmFtZXMobWVhbl9jdCkgPSBtZWFuX2N0WywxXQptZWFuX2N0ID0gbWVhbl9jdFssLTFdCmNvbG5hbWVzKG1lYW5fY3QpID0gcGFzdGUwKHJlcChjb2xuYW1lcyhtX2N0X2ZyZXNoKSwgMiksIHJlcChjKCJfZnJlc2giLCAiX2Zyb3plbiIpLCBlYWNoID0gNSkpCgpwYXIobWZyb3cgPSBjKDIsMykpCnBsb3QobWVhbl9jdCRDaG9sYW5naW9jeXRlc19mcmVzaCwgbWVhbl9jdCRDaG9sYW5naW9jeXRlc19mcm96ZW4sIHBjaCA9IDIwLCBjZXggPSAwLjUsIHhsaW0gPSBjKC04LDUpLCB5bGltID0gYygtOCw1KSkKdGl0bGUoIkNob2xhbmdpb2N5dGVzIikKYWJsaW5lKDAsMSkKcGxvdChtZWFuX2N0JEVuZG90aGVsaWFsX2ZyZXNoLCBtZWFuX2N0JEVuZG90aGVsaWFsX2Zyb3plbiwgcGNoID0gMjAsIGNleCA9IDAuNSwgeGxpbSA9IGMoLTgsNSksIHlsaW0gPSBjKC04LDUpKQp0aXRsZSgiRW5kb3RoZWxpYWwiKQphYmxpbmUoMCwxKQpwbG90KG1lYW5fY3QkSGVwYXRvY3l0ZXNfZnJlc2gsIG1lYW5fY3QkSGVwYXRvY3l0ZXNfZnJvemVuLCBwY2ggPSAyMCwgY2V4ID0gMC41LCB4bGltID0gYygtMTAsNiksIHlsaW0gPSBjKC0xMCw2KSkKdGl0bGUoIkhlcGF0b2N5dGVzIikKYWJsaW5lKDAsMSkKcGxvdChtZWFuX2N0JEltbXVuZV9mcmVzaCwgbWVhbl9jdCRJbW11bmVfZnJvemVuLCBwY2ggPSAyMCwgY2V4ID0gMC41LCB4bGltID0gYygtOCw1KSwgeWxpbSA9IGMoLTgsNSkpCnRpdGxlKCJJbW11bmUiKQphYmxpbmUoMCwxKQpwbG90KG1lYW5fY3QkTWVzZW5jaHltYWxfZnJlc2gsIG1lYW5fY3QkTWVzZW5jaHltYWxfZnJvemVuLCBwY2ggPSAyMCwgY2V4ID0gMC41LCB4bGltID0gYygtOCw1KSwgeWxpbSA9IGMoLTgsNSkpCnRpdGxlKCJNZXNlbmNoeW1hbCIpCmFibGluZSgwLDEpCnBsb3Qocm93TWVhbnMobWVhbl9jdFssMTo1XSksIHJvd01lYW5zKG1lYW5fY3RbLDY6MTBdKSwgcGNoID0gMjAsIGNleCA9IDAuNSwgeGxpbSA9IGMoLTgsNSksIHlsaW0gPSBjKC04LDUpKQp0aXRsZSgiQWxsIikKYWJsaW5lKDAsMSkKYGBgCgoKIyMgU3VwcGxlbWVudGFyeQpVTUFQIHdpdGggaGVhbHRoeSBkb25vcnMgc3BsaXQKCmBgYHtyLCBmaWcuaGVpZ2h0PTIsIGZpZy53aWR0aD0zfQpwbG90X2RmID0gZGF0YS5mcmFtZShoY2VsbHNfY3NzQHJlZHVjdGlvbnMkdW1hcF9jc3NAY2VsbC5lbWJlZGRpbmdzKQpwbG90X2RmJERvbm9yID0gZmFjdG9yKGhjZWxsc19jc3NAbWV0YS5kYXRhJERvbm9yKQpwbG90X2RmJERvbm9yID0gcGx5cjo6cmV2YWx1ZShwbG90X2RmJERvbm9yLCBjKCJIRDEiID0gInNjX0gxIiwgIkhEMiIgPSAic2NfSDIiLCAiSEQzIiA9ICJzY19IMyIpKQoKcGx0ID0gZ2dwbG90KHBsb3RfZGZbc2FtcGxlKDE6bnJvdyhwbG90X2RmKSwgbnJvdyhwbG90X2RmKSwgcmVwbGFjZSA9IEYpLF0sIAogICAgICAgICAgICAgYWVzKHggPSBVTUFDU1NfMSwgeSA9IFVNQUNTU18yLCBjb2xvdXIgPSBEb25vcikpKwogIGZhY2V0X3dyYXAofkRvbm9yKSsKICBnZW9tX3BvaW50KHNpemUgPSAwLjE1KSsKICBndWlkZXMoY29sb3VyID0gZ3VpZGVfbGVnZW5kKG92ZXJyaWRlLmFlcyA9IGxpc3Qoc2l6ZSA9IDMpLCB0aXRsZSA9ICJEb25vcnMiKSkrCiAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBjb2xkb24pKwogIHRoZW1lX2NsYXNzaWMoKSsKICB0aF9nZW4rCiAgdGhlbWUoYXhpcy5saW5lID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGlja3MgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRleHQgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMCksCiAgICAgICAgYXNwZWN0LnJhdGlvID0gMSkKCnBkZigiZmlndXJlX3BhbmVscy9maWcxL3VtYXBfZnJlc2hfZG9ub3JzX3NwbGl0LnBkZiIsIAogICAgdXNlRGluZ2JhdHMgPSBGLCBoZWlnaHQgPSA0LCB3aWR0aCA9IDcpCnByaW50KHBsdCkKZGV2Lm9mZigpCnBuZygiZmlndXJlX3BhbmVscy9maWcxL3VtYXBfZnJlc2hfZG9ub3JzX3NwbGl0LnBuZyIsIAogICAgaGVpZ2h0PTgsIHdpZHRoPTEwLCB1bml0PSJjbSIsIHJlcz02MDAsIGFudGlhbGlhcyA9ICJzdWJwaXhlbCIpCnByaW50KHBsdCkKZGV2Lm9mZigpCnBkZigiZmlndXJlX3BhbmVscy9maWcxL3VtYXBfZnJlc2hfZG9ub3JzX25vTGVnX3NwbGl0LnBkZiIsIAogICAgdXNlRGluZ2JhdHMgPSBGLCBoZWlnaHQgPSA0LCB3aWR0aCA9IDcpCnByaW50KHBsdCt0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpKQpkZXYub2ZmKCkKcG5nKCJmaWd1cmVfcGFuZWxzL2ZpZzEvdW1hcF9mcmVzaF9kb25vcnNfbm9MZWdfc3BsaXQucG5nIiwgCiAgICBoZWlnaHQ9OCwgd2lkdGg9MTAsIHVuaXQ9ImNtIiwgcmVzPTYwMCwgYW50aWFsaWFzID0gInN1YnBpeGVsIikKcHJpbnQocGx0K3RoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikpCmRldi5vZmYoKQpgYGAKCkJveHBsb3Qgd2l0aCBuVU1JCgpgYGB7cn0KcGxvdF9kZiA9IGRhdGEuZnJhbWUoaGNlbGxzX2Nzc0ByZWR1Y3Rpb25zJHVtYXBfY3NzQGNlbGwuZW1iZWRkaW5ncykKcGxvdF9kZiRuYW1lc19tYWpvciA9IGFzLmNoYXJhY3RlcihoY2VsbHNfY3NzQG1ldGEuZGF0YSRuYW1lc19tYWpvcikKcGxvdF9kZiRuYW1lc19tYWpvcltwbG90X2RmJG5hbWVzX21ham9yPT0iVCBjZWxscyIgfCAKICAgICAgICAgICAgICAgICAgICAgIHBsb3RfZGYkbmFtZXNfbWFqb3I9PSJCIGNlbGxzIiB8IAogICAgICAgICAgICAgICAgICAgICAgcGxvdF9kZiRuYW1lc19tYWpvcj09Ik1hY3JvcGhhZ2VzIiB8CiAgICAgICAgICAgICAgICAgICAgICBwbG90X2RmJG5hbWVzX21ham9yPT0iRENzIl0gPSAiSW1tdW5lIgpwbG90X2RmJG5hbWVzX21ham9yW3Bsb3RfZGYkbmFtZXNfbWFqb3I9PSJTdGVsbGF0ZSBjZWxscyJdID0gIk1lc2VuY2h5bWFsIgpwbG90X2RmJG5hbWVzX21ham9yW3Bsb3RfZGYkbmFtZXNfbWFqb3I9PSJFbmRvdGhlbGlhbCBjZWxscyJdID0gIkVuZG90aGVsaWFsIgpwbG90X2RmJG5HZW5lID0gaGNlbGxzX2Nzc0BtZXRhLmRhdGEkbkZlYXR1cmVfU0NUCnBsb3RfZGYgPSBwbG90X2RmWywzOjVdCnNhdmVSRFMocGxvdF9kZiwgIi4vdG9fc2VuZC9kZl9jZWxsdHlwZXNfdW1pX2dlbmUuUkRTIikgIyBwbG90dGVkIGJ5IEFnYQpgYGAKClVNQVAgd2l0aCBhbGwgY2VsbCB0eXBlcwoKYGBge3J9CnBsb3RfZGYgPSBkYXRhLmZyYW1lKGhjZWxsc19jc3NAcmVkdWN0aW9ucyR1bWFwX2Nzc0BjZWxsLmVtYmVkZGluZ3MpCmNvbG5hbWVzKHBsb3RfZGYpID0gYygiVU1BUENTU18xIiwgIlVNQVBDU1NfMiIpCnBsb3RfZGYkbmFtZXNfbWFqb3IgPSBhcy5jaGFyYWN0ZXIoaGNlbGxzX2Nzc0BtZXRhLmRhdGEkbmFtZXNfbWFqb3IpCnBsb3RfZGYkbmFtZXNfbWFqb3JbcGxvdF9kZiRuYW1lc19tYWpvcj09IlQgY2VsbHMiIHwgCiAgICAgICAgICAgICAgICAgICAgICBwbG90X2RmJG5hbWVzX21ham9yPT0iQiBjZWxscyIgfCAKICAgICAgICAgICAgICAgICAgICAgIHBsb3RfZGYkbmFtZXNfbWFqb3I9PSJNYWNyb3BoYWdlcyIgfAogICAgICAgICAgICAgICAgICAgICAgcGxvdF9kZiRuYW1lc19tYWpvcj09IkRDcyJdID0gIkltbXVuZSIKcGxvdF9kZiRuYW1lc19tYWpvcltwbG90X2RmJG5hbWVzX21ham9yPT0iU3RlbGxhdGUgY2VsbHMiXSA9ICJNZXNlbmNoeW1hbCIKcGxvdF9kZiRuYW1lc19tYWpvcltwbG90X2RmJG5hbWVzX21ham9yPT0iRW5kb3RoZWxpYWwgY2VsbHMiXSA9ICJFbmRvdGhlbGlhbCIKcGxvdF9kZiRuYW1lc19jbHVzdGVycyA9IGFzLmNoYXJhY3RlcihoY2VsbHNfY3NzQG1ldGEuZGF0YSRuYW1lc19jbHVzdGVycykKcGxvdF9kZiRuYW1lc19jbHVzdGVyc1tncmVwbCgiSGVwYXRvY3l0ZXMgIiwgcGxvdF9kZiRuYW1lc19jbHVzdGVycyldID0gIkhlcGF0b2N5dGVzIgpwbG90X2RmJG5hbWVzX2NsdXN0ZXJzW2dyZXBsKCJjZW50cmFsIHZlaW4iLCBwbG90X2RmJG5hbWVzX2NsdXN0ZXJzKV0gPSAiTFNFQyBwZXJpY2VudHJhbCIKcGxvdF9kZiRuYW1lc19jbHVzdGVyc1tncmVwbCgicG9ydGFsIHZlaW4iLCBwbG90X2RmJG5hbWVzX2NsdXN0ZXJzKV0gPSAiTFNFQyBwZXJpcG9ydGFsIgpwbG90X2RmJG5hbWVzX2NsdXN0ZXJzW2dyZXBsKCJpbnRlcmFjdGlvbiIsIHBsb3RfZGYkbmFtZXNfY2x1c3RlcnMpIHwKICAgICAgICAgICAgICAgICAgICAgICAgIGdyZXBsKCJtaXgiLCBwbG90X2RmJG5hbWVzX2NsdXN0ZXJzKSBdID0gIkRvdWJsZXRzIgpwbG90X2RmJG5hbWVzX2NsdXN0ZXJzID0gZmFjdG9yKHBsb3RfZGYkbmFtZXNfY2x1c3RlcnMsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxldmVscyA9IGMoIkNob2xhbmdpb2N5dGVzIiwgIkxTRUMgcGVyaXBvcnRhbCIsICJMU0VDIHBlcmljZW50cmFsIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiRW5kb3RoZWxpYWwgY2VsbHMgKG5vbi1MU0VDKSIsICJIZXBhdG9jeXRlcyIsICJLdXBmZmVyIGNlbGxzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJNYWNyb3BoYWdlcyIsICJjRENzIiwgInBEQ3MiLCAiYWItVCBjZWxscyIsICJnZC1UIGNlbGxzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJCIGNlbGxzIiwgIlBsYXNtYWJsYXN0cyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiU3RlbGxhdGUgY2VsbHMiLCAiRGl2aWRpbmcgY2VsbHMiLCAiRG91YmxldHMiKSkKCnBsdHVtYXAgPSBnZ3Bsb3QocGxvdF9kZiwgYWVzKHkgPSBVTUFQQ1NTXzIsIHggPSBVTUFQQ1NTXzEsIGNvbG91ciA9IG5hbWVzX2NsdXN0ZXJzKSkrCiAgZ2VvbV9wb2ludChzaXplID0gcG9pbnRzaXplKSsKICBsYWJzKGNvbG91ciA9ICJDZWxsIFR5cGUiKSsKICBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcyA9IGMoY29sc2FsbGN0LCAiT3RoZXIiID0gImdyZXk4OCIpKSsKICBndWlkZXMoY29sb3VyID0gZ3VpZGVfbGVnZW5kKG92ZXJyaWRlLmFlcyA9IGxpc3Qoc2l6ZSA9IDIpKSkrCiAgdGhlbWUoYXNwZWN0LnJhdGlvID0gMSwKICAgICAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwKSwKICAgICAgICBheGlzLmxpbmUgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy50ZXh0ID0gZWxlbWVudF9ibGFuaygpKQoKcGRmKCJmaWd1cmVfcGFuZWxzL2ZpZzEvdW1hcF9oX2FsbF9jZWxsdHlwZXMucGRmIiwgaGVpZ2h0ID0gNSwgd2lkdGggPSA2LCB1c2VEaW5nYmF0cyA9IEYpCnByaW50KHBsdHVtYXApCmRldi5vZmYoKQpwbmcoImZpZ3VyZV9wYW5lbHMvZmlnMS91bWFwX2hfYWxsX2NlbGx0eXBlcy5wbmciLCBoZWlnaHQgPSAzMjUsIHdpZHRoID0gNDAwLCBhbnRpYWxpYXMgPSAic3VicGl4ZWwiKQpwcmludChwbHR1bWFwKQpkZXYub2ZmKCkKCnBsb3RfZGYkbmFtZXNfY2x1c3RlcnNbcGxvdF9kZiRuYW1lc19tYWpvciE9IkltbXVuZSJdID0gIkRvdWJsZXRzIgpsZXZlbHMocGxvdF9kZiRuYW1lc19jbHVzdGVycylbbGV2ZWxzKHBsb3RfZGYkbmFtZXNfY2x1c3RlcnMpPT0iRG91YmxldHMiXSA9ICJPdGhlciIKcGx0dW1hcCA9IGdncGxvdChwbG90X2RmLCBhZXMoeSA9IFVNQVBDU1NfMiwgeCA9IFVNQVBDU1NfMSwgY29sb3VyID0gbmFtZXNfY2x1c3RlcnMpKSsKICBnZW9tX3BvaW50KHNpemUgPSBwb2ludHNpemUpKwogIGxhYnMoY29sb3VyID0gIkNlbGwgVHlwZSIpKwogIHNjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzID0gYyhjb2xzYWxsY3QsICJPdGhlciIgPSAiZ3JleTg4IikpKwogIGd1aWRlcyhjb2xvdXIgPSBndWlkZV9sZWdlbmQob3ZlcnJpZGUuYWVzID0gbGlzdChzaXplID0gMikpKSsKICB0aGVtZShhc3BlY3QucmF0aW8gPSAxLAogICAgICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDApLAogICAgICAgIGF4aXMubGluZSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRleHQgPSBlbGVtZW50X2JsYW5rKCkpCmBgYAoKSGVhdG1hcCB3aXRoIG1hcmtlcnMgZm9yIGFsbCBjZWxsIHR5cGVzCgpgYGB7cn0KcGxvdF9kZiA9IGRhdGEuZnJhbWUoaGNlbGxzX2Nzc0ByZWR1Y3Rpb25zJHVtYXBfY3NzQGNlbGwuZW1iZWRkaW5ncykKY29sbmFtZXMocGxvdF9kZikgPSBjKCJVTUFQQ1NTXzEiLCAiVU1BUENTU18yIikKcGxvdF9kZiRuYW1lc19tYWpvciA9IGFzLmNoYXJhY3RlcihoY2VsbHNfY3NzQG1ldGEuZGF0YSRuYW1lc19tYWpvcikKcGxvdF9kZiRuYW1lc19tYWpvcltwbG90X2RmJG5hbWVzX21ham9yPT0iVCBjZWxscyIgfCAKICAgICAgICAgICAgICAgICAgICAgIHBsb3RfZGYkbmFtZXNfbWFqb3I9PSJCIGNlbGxzIiB8IAogICAgICAgICAgICAgICAgICAgICAgcGxvdF9kZiRuYW1lc19tYWpvcj09Ik1hY3JvcGhhZ2VzIiB8CiAgICAgICAgICAgICAgICAgICAgICBwbG90X2RmJG5hbWVzX21ham9yPT0iRENzIl0gPSAiSW1tdW5lIgpwbG90X2RmJG5hbWVzX21ham9yW3Bsb3RfZGYkbmFtZXNfbWFqb3I9PSJTdGVsbGF0ZSBjZWxscyJdID0gIk1lc2VuY2h5bWFsIgpwbG90X2RmJG5hbWVzX21ham9yW3Bsb3RfZGYkbmFtZXNfbWFqb3I9PSJFbmRvdGhlbGlhbCBjZWxscyJdID0gIkVuZG90aGVsaWFsIgpwbG90X2RmJG5hbWVzX2NsdXN0ZXJzID0gYXMuY2hhcmFjdGVyKGhjZWxsc19jc3NAbWV0YS5kYXRhJG5hbWVzX2NsdXN0ZXJzKQpwbG90X2RmJG5hbWVzX2NsdXN0ZXJzW2dyZXBsKCJIZXBhdG9jeXRlcyAiLCBwbG90X2RmJG5hbWVzX2NsdXN0ZXJzKV0gPSAiSGVwYXRvY3l0ZXMiCnBsb3RfZGYkbmFtZXNfY2x1c3RlcnNbZ3JlcGwoImNlbnRyYWwgdmVpbiIsIHBsb3RfZGYkbmFtZXNfY2x1c3RlcnMpXSA9ICJMU0VDIHBlcmljZW50cmFsIgpwbG90X2RmJG5hbWVzX2NsdXN0ZXJzW2dyZXBsKCJwb3J0YWwgdmVpbiIsIHBsb3RfZGYkbmFtZXNfY2x1c3RlcnMpXSA9ICJMU0VDIHBlcmlwb3J0YWwiCnBsb3RfZGYkbmFtZXNfY2x1c3RlcnNbZ3JlcGwoImludGVyYWN0aW9uIiwgcGxvdF9kZiRuYW1lc19jbHVzdGVycykgfAogICAgICAgICAgICAgICAgICAgICAgICAgZ3JlcGwoIm1peCIsIHBsb3RfZGYkbmFtZXNfY2x1c3RlcnMpIF0gPSAiRG91YmxldHMiCnBsb3RfZGYkbmFtZXNfY2x1c3RlcnMgPSBmYWN0b3IocGxvdF9kZiRuYW1lc19jbHVzdGVycywgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGV2ZWxzID0gYygiQ2hvbGFuZ2lvY3l0ZXMiLCAiTFNFQyBwZXJpcG9ydGFsIiwgIkxTRUMgcGVyaWNlbnRyYWwiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJFbmRvdGhlbGlhbCBjZWxscyAobm9uLUxTRUMpIiwgIkhlcGF0b2N5dGVzIiwgIkt1cGZmZXIgY2VsbHMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIk1hY3JvcGhhZ2VzIiwgImNEQ3MiLCAicERDcyIsICJhYi1UIGNlbGxzIiwgImdkLVQgY2VsbHMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkIgY2VsbHMiLCAiUGxhc21hYmxhc3RzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJTdGVsbGF0ZSBjZWxscyIsICJEaXZpZGluZyBjZWxscyIsICJEb3VibGV0cyIpKQpwbG90X2RmID0gcGxvdF9kZltwbG90X2RmJG5hbWVzX2NsdXN0ZXJzIT0iRG91YmxldHMiLF0KCm5tZyA9IGMoIktSVDciLCAiQ0QyNCIsICAiTElMUkE0IiwgIklSRjciLCAgIkZDRVIxQSIsICJDTEVDMTBBIiwgICJDQ0wyMyIsIkNMRUMxQiIsICAiSU5NVCIsIlNFTFAiLCAgCiAgICAgICAgIk1BUkNPIiwiQ0Q1TCIsICAiQ1lQMkUxIiwiT1JNMiIsICAiTVM0QTEiLCJDRDc5QSIsICAiQ0xFQzE0QSIsIkVETlJCIiwgICJJR0xDMiIsIkNEMjciLCAgCiAgICAgICAgIlRSREMiLCJLTFJEMSIsICAiVFJBQyIsIkNEM0UiLCAgIkRDTiIsIkNPTEVDMTEiLCAgIlMxMDBBMTIiLCJDRDMwMEUiKQpubWcgPSBubWdbYygxLDIsMTMsMTQsMTcsMTgsNyw4LDksMTAsMjUsMjYsMjcsMjgsMTEsMTIsNSw2LDMsNCwyMywyNCwyMSwyMiwxNSwxNiwxOSwyMCldCgptMSA9IEdldEFzc2F5RGF0YShoY2VsbHNfY3NzLCBzbG90PSJkYXRhIilbbm1nLHJvd25hbWVzKHBsb3RfZGYpXQptX2N0X2ZyZXNoID0gYXBwbHkobTEsIDEsIGZ1bmN0aW9uKHgpIHRhcHBseSh4LCBhcy5jaGFyYWN0ZXIocGxvdF9kZiRuYW1lc19jbHVzdGVycyksIG1lYW4pKQptX2N0X2ZyZXNoW21fY3RfZnJlc2g+NF0gPSA0LjAxCm1fY3RfZnJlc2hbbV9jdF9mcmVzaDwoLTQpXSA9IC00LjAxCgphbm5vdF9kZiA9IHVuaXF1ZShwbG90X2RmWyxjKDMsNCldKQphbm5vdF9kZiA9IGRhdGEuZnJhbWUocm93Lm5hbWVzID0gYW5ub3RfZGYkbmFtZXNfY2x1c3RlcnMsICJjdCIgPSBhbm5vdF9kZiRuYW1lc19tYWpvcikKaGVhdCA9IHBoZWF0bWFwOjpwaGVhdG1hcChzY2FsZShtX2N0X2ZyZXNoW2MoNCw3LDEwLDksNSwxNCwxMSw4LDMsMTIsMSw2LDIsMTMpLF0pLCAKICAgICAgICAgICAgICAgICAgICAgICAgICBjbHVzdGVyaW5nX21ldGhvZCA9ICJ3YXJkLkQyIiwgdHJlZWhlaWdodF9yb3cgPSAwLAogICAgICAgICAgICAgICAgICAgICAgICAgIHRyZWVoZWlnaHRfY29sID0gMjAsIGZvbnRzaXplX3JvdyA9IDgsIGZvbnRzaXplX2NvbCA9IDgsCiAgICAgICAgICAgICAgICAgICAgICAgICAgY2x1c3Rlcl9jb2xzID0gRiwgY2x1c3Rlcl9yb3dzID0gRiwKICAgICAgICAgICAgICAgICAgICAgICAgICBhbm5vdGF0aW9uX3JvdyA9IGFubm90X2RmLCBhbm5vdGF0aW9uX2NvbG9ycyA9IGxpc3QoY3QgPSBjb2xzbWFqb3JbLTZdKSwKICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvciA9IGNvbG9yUmFtcFBhbGV0dGUocmV2KGJyZXdlci5wYWwobiA9IDksIG5hbWUgPSAiUmRCdSIpKSkoMTAwKSkKCnBkZigiZmlndXJlX3BhbmVscy9maWcxL2hlYXRtYXBfYWxsX2NlbGx0eXBlcy5wZGYiLCBoZWlnaHQgPSAzLjUsIHdpZHRoID0gNywgdXNlRGluZ2JhdHMgPSBGKQpwcmludChoZWF0KQpkZXYub2ZmKCkKYGBgCgoKIyBGaWd1cmUgMgojIyBNYWluIEZpZ3VyZQpVTUFQIHdpdGggY2VsbCB0eXBlcwoKYGBge3J9CmFsbGNlbGxzX2NzcyA9IHJlYWRSRFMoZmlsZSA9ICJkYXRhL3Byb2Nlc3NlZC9hbGxjZWxsc19jc3NfcmVhbm5vdC5SRFMiKQoKbG9hZChmaWxlID0gImRhdGEvcHJvY2Vzc2VkL2hlYWx0aHlfc3JhdF9iZWZvcmVGaWx0ZXJpbmcuUkRhdGEiKQpsb2FkKGZpbGUgPSAiZGF0YS9wcm9jZXNzZWQvY29uZF9zcmF0X2JlZm9yZUZpbHRlcmluZy5SRGF0YSIpCmBgYAoKYGBge3J9CnBsb3RfZGYgPSBhbGxjZWxsc19jc3NAbWV0YS5kYXRhCnBsb3RfZGYgPSBjYmluZChwbG90X2RmLCBhbGxjZWxsc19jc3NAcmVkdWN0aW9ucyR1bWFwX2Nzc0BjZWxsLmVtYmVkZGluZ3MpCnBsb3RfZGYkQ29uZGl0aW9uID0gZmFjdG9yKHBsb3RfZGYkQ29uZGl0aW9uLCBsZXZlbHMgPSBjKCJoZWFsdGh5IiwgImVtYm9saXNlZCIsICJyZWdlbmVyYXRpbmciKSkKcGxvdF9kZiRtYWpvcl9jdFtpcy5uYShwbG90X2RmJG1ham9yX2N0KV0gPSBwbG90X2RmJGFsbGNlbGxzX21ham9yW2lzLm5hKHBsb3RfZGYkbWFqb3JfY3QpXQpwbG90X2RmJG1ham9yX2N0W3Bsb3RfZGYkbWFqb3JfY3Q9PSJEaXZpZGluZyBjZWxscyJdID0gIkltbXVuZSIgIyB0aGUgZGV0ZWN0ZWQgZGl2aWRpbmcgY2VsbHMgYXJlIG1vc3RseSAoaWYgbm90IGFsbCkgaW1tdW5lIApwbG90X2RmJG1ham9yX2N0ID0gZmFjdG9yKHBsb3RfZGYkbWFqb3JfY3QsIGxldmVscyA9IGMoIkhlcGF0b2N5dGVzIiwgIkVuZG90aGVsaWFsIiwgIkNob2xhbmdpb2N5dGVzIiwgIkltbXVuZSIsICJNZXNlbmNoeW1hbCIsICJEb3VibGV0cyIpKQoKcGx0dW1hcCA9IGdncGxvdChwbG90X2RmLCBhZXMoeSA9IFVNQVBDU1NfMiwgeCA9IFVNQVBDU1NfMSwgY29sb3VyID0gbWFqb3JfY3QpKSsKICBnZW9tX3BvaW50KHNpemUgPSBwb2ludHNpemUpKwogIGxhYnMoY29sb3VyID0gIkNlbGwgVHlwZSIpKwogIHNjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzID0gYyhjb2xzbWFqb3IsICJEb3VibGV0cyIgPSAiZ3JleTkwIikpKwogIGd1aWRlcyhjb2xvdXIgPSBndWlkZV9sZWdlbmQob3ZlcnJpZGUuYWVzID0gbGlzdChzaXplID0gMikpKSsKICB0aGVtZShhc3BlY3QucmF0aW8gPSAxLAogICAgICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDApLAogICAgICAgIGF4aXMubGluZSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRleHQgPSBlbGVtZW50X2JsYW5rKCkpCgpwZGYoImZpZ3VyZV9wYW5lbHMvZmlnMi91bWFwX21ham9yX2NlbGx0eXBlcy5wZGYiLCBoZWlnaHQgPSA1LCB3aWR0aCA9IDYsIHVzZURpbmdiYXRzID0gRikKcHJpbnQocGx0dW1hcCkKZGV2Lm9mZigpCnBuZygiZmlndXJlX3BhbmVscy9maWcyL3VtYXBfbWFqb3JfY2VsbHR5cGVzLnBuZyIsIGhlaWdodCA9IDMyNSwgd2lkdGggPSA0MDAsIGFudGlhbGlhcyA9ICJzdWJwaXhlbCIpCnByaW50KHBsdHVtYXApCmRldi5vZmYoKQpgYGAKClVNQVAgd2l0aCBhbGwgY2VsbCB0eXBlcwoKYGBge3J9CnBsb3RfZGYgPSBhbGxjZWxsc19jc3NAbWV0YS5kYXRhCnBsb3RfZGYgPSBjYmluZChwbG90X2RmLCBhbGxjZWxsc19jc3NAcmVkdWN0aW9ucyR1bWFwX2Nzc0BjZWxsLmVtYmVkZGluZ3MpCnBsb3RfZGYkQ29uZGl0aW9uID0gZmFjdG9yKHBsb3RfZGYkQ29uZGl0aW9uLCBsZXZlbHMgPSBjKCJoZWFsdGh5IiwgImVtYm9saXNlZCIsICJyZWdlbmVyYXRpbmciKSkKcGxvdF9kZiRhbGxjZWxsc19zaW1wW2dyZXBsKCJpbnRlcmFjdGlvbiIsIHBsb3RfZGYkYWxsY2VsbHNfc2ltcCldID0gIkRvdWJsZXRzIgpwbG90X2RmJGFsbGNlbGxzX3NpbXBbZ3JlcGwoIkhlcGF0b2N5dGVzICIsIHBsb3RfZGYkYWxsY2VsbHNfc2ltcCldID0gIkhlcGF0b2N5dGVzIgpwbG90X2RmJGFsbGNlbGxzX3NpbXAgPSBmYWN0b3IocGxvdF9kZiRhbGxjZWxsc19zaW1wLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxldmVscyA9IGMoIkNob2xhbmdpb2N5dGVzIiwgIkxTRUMgcGVyaXBvcnRhbCIsICJMU0VDIHBlcmljZW50cmFsIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJFbmRvdGhlbGlhbCBjZWxscyAobm9uLUxTRUMpIiwgIkhlcGF0b2N5dGVzIiwgIkt1cGZmZXIgY2VsbHMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiTWFjcm9waGFnZXMiLCAiY0RDcyIsICJwRENzIiwgImFiLVQgY2VsbHMiLCAiZ2QtVCBjZWxscyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJCIGNlbGxzIiwgIlBsYXNtYWJsYXN0cyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJTdGVsbGF0ZSBjZWxscyIsICJEaXZpZGluZyBjZWxscyIsICJEb3VibGV0cyIpKQoKcGx0dW1hcCA9IGdncGxvdChwbG90X2RmLCBhZXMoeSA9IFVNQVBDU1NfMiwgeCA9IFVNQVBDU1NfMSwgY29sb3VyID0gYWxsY2VsbHNfc2ltcCkpKwogIGdlb21fcG9pbnQoc2l6ZSA9IHBvaW50c2l6ZSkrCiAgbGFicyhjb2xvdXIgPSAiQ2VsbCBUeXBlIikrCiAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBjb2xzYWxsY3QpKwogIGd1aWRlcyhjb2xvdXIgPSBndWlkZV9sZWdlbmQob3ZlcnJpZGUuYWVzID0gbGlzdChzaXplID0gMikpKSsKICB0aGVtZShhc3BlY3QucmF0aW8gPSAxLAogICAgICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDApLAogICAgICAgIGF4aXMubGluZSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRleHQgPSBlbGVtZW50X2JsYW5rKCkpCgpwZGYoImZpZ3VyZV9wYW5lbHMvZmlnMi91bWFwX2FsbF9jZWxsdHlwZXMucGRmIiwgaGVpZ2h0ID0gNSwgd2lkdGggPSA2LCB1c2VEaW5nYmF0cyA9IEYpCnByaW50KHBsdHVtYXApCmRldi5vZmYoKQpwbmcoImZpZ3VyZV9wYW5lbHMvZmlnMi91bWFwX2FsbF9jZWxsdHlwZXMucG5nIiwgaGVpZ2h0ID0gMzI1LCB3aWR0aCA9IDQwMCwgYW50aWFsaWFzID0gInN1YnBpeGVsIikKcHJpbnQocGx0dW1hcCkKZGV2Lm9mZigpCmBgYAoKUHJvcG9ydGlvbiBvZiBlYWNoIGNlbGwgdHlwZSBwZXIgY29uZGl0aW9uCgpgYGB7cn0KZGZfY250ID0gdGFibGUocGxvdF9kZiRhbGxjZWxsc19zaW1wLCBwbG90X2RmJENvbmRpdGlvbilbLWMoMTUsMTYpLF0KZGZfY250X2hlcCA9IHJlc2hhcGUyOjptZWx0KGFwcGx5KGRmX2NudCwgMiwgZnVuY3Rpb24oeCkgcm91bmQoeC9zdW0oeCkqMTAwLCAxKSlbNSxdKQpkZl9jbnRfbm9oZXAgPSByZXNoYXBlMjo6bWVsdChhcHBseShkZl9jbnRbLTUsXSwgMiwgZnVuY3Rpb24oeCkgcm91bmQoeC9zdW0oeCkqMTAwLCAxKSkpCgpkZl9jbnRfYWxsID0gcmJpbmQoZGF0YS5mcmFtZSgiVmFyMSIgPSAiSGVwYXRvY3l0ZXMiLCAiVmFyMiIgPSByb3duYW1lcyhkZl9jbnRfaGVwKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJ2YWx1ZSIgPSBkZl9jbnRfaGVwJHZhbHVlKSwKICAgICAgICAgICAgICAgICAgIGRmX2NudF9ub2hlcCkKCm1hdF9jbnRfYWxsID0gcmVzaGFwZTI6OmRjYXN0KGRhdGEgPSBkZl9jbnRfYWxsLCBmb3JtdWxhID0gVmFyMSB+IFZhcjIsIHZhbHVlLnZhciA9ICJ2YWx1ZSIpCnJvd25hbWVzKG1hdF9jbnRfYWxsKSA9IG1hdF9jbnRfYWxsJFZhcjEKbWF0X2NudF9hbGwgPSBtYXRfY250X2FsbFssLTFdCmN0b3JkID0gaGNsdXN0KGRpc3QobWF0X2NudF9hbGxbLGMoMiwxLDMpXSkpJG9yZGVyCmN0b3JkID0gYyg3LCA0LCAxMCwgOSwgNSwgMTQsIDExLCA4LCAzLCAxMiwxLDYsMiwxMykKCmFubm90X2RmID0gdW5pcXVlKHBsb3RfZGZbLGMoIm1ham9yX2N0IiwiYWxsY2VsbHNfc2ltcCIpXSkKYW5ub3RfZGYgPSBkYXRhLmZyYW1lKHJvdy5uYW1lcyA9IGFubm90X2RmJGFsbGNlbGxzX3NpbXAsICJjdCIgPSBhbm5vdF9kZiRtYWpvcl9jdCkKaGVhdHAgPSBwaGVhdG1hcDo6cGhlYXRtYXAobWF0X2NudF9hbGxbY3RvcmQsYygyLDEsMyldLCBjbHVzdGVyX2NvbHMgPSBGLCBjbHVzdGVyX3Jvd3MgPSBGLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgdHJlZWhlaWdodF9yb3cgPSBGLCBkaXNwbGF5X251bWJlcnMgPSBULCBnYXBzX3JvdyA9IGMoMSwxKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgIG51bWJlcl9jb2xvciA9IGMoImJsYWNrIiwgIndoaXRlIilbYXMuaW50ZWdlcihtYXRfY250X2FsbFtjdG9yZCxjKDIsMSwzKV0+NTApKzFdLAogICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvciA9IGNvbG9yUmFtcFBhbGV0dGUoYnJld2VyLnBhbChuID0gOSwgbmFtZSA9ICJCbHVlcyIpKSgxMDApLAogICAgICAgICAgICAgICAgICAgICAgICAgICBmb250c2l6ZV9yb3cgPSA4LCBmb250c2l6ZV9jb2wgPSA4LAogICAgICAgICAgICAgICAgICAgICAgICAgICBhbm5vdGF0aW9uX3JvdyA9IGFubm90X2RmLCBhbm5vdGF0aW9uX2NvbG9ycyA9IGxpc3QoY3QgPSBjb2xzbWFqb3JbLTZdKSkKCnBkZigiZmlndXJlX3BhbmVscy9maWcyL2hlYXRtYXBfYWxsX2NlbGx0eXBlc19wcm9wLnBkZiIsIGhlaWdodCA9IDMuNSwgd2lkdGggPSA1LCB1c2VEaW5nYmF0cyA9IEYpCnByaW50KGhlYXRwKQpkZXYub2ZmKCkKYGBgCgpVTUFQIHdpdGggY29uZGl0aW9ucwoKYGBge3J9CnJhbmRvbXJvd3MgPSBzYW1wbGUoMTpucm93KHBsb3RfZGYpLCBzaXplID0gbnJvdyhwbG90X2RmKSwgcmVwbGFjZSA9IEYpCnBsdHVtYXBjb25kID0gZ2dwbG90KHBsb3RfZGZbcmFuZG9tcm93cyxdLCBhZXMoeSA9IFVNQVBDU1NfMiwgeCA9IFVNQVBDU1NfMSwgY29sb3VyID0gQ29uZGl0aW9uKSkrCiAgZ2VvbV9wb2ludChzaXplID0gcG9pbnRzaXplKSsKICBsYWJzKGNvbG91ciA9ICJDb25kaXRpb24iKSsKICBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcyA9IGNvbGNvbmQpKwogIGd1aWRlcyhjb2xvdXIgPSBndWlkZV9sZWdlbmQob3ZlcnJpZGUuYWVzID0gbGlzdChzaXplID0gMikpKSsKICB0aGVtZShhc3BlY3QucmF0aW8gPSAxLAogICAgICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDApLAogICAgICAgIGF4aXMubGluZSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRleHQgPSBlbGVtZW50X2JsYW5rKCkpCgpwZGYoImZpZ3VyZV9wYW5lbHMvZmlnMi91bWFwX2NvbmRpdGlvbi5wZGYiLCBoZWlnaHQgPSA1LCB3aWR0aCA9IDYsIHVzZURpbmdiYXRzID0gRikKcHJpbnQocGx0dW1hcGNvbmQpCmRldi5vZmYoKQpwbmcoImZpZ3VyZV9wYW5lbHMvZmlnMi91bWFwX2NvbmRpdGlvbi5wbmciLCBoZWlnaHQgPSAzMjUsIHdpZHRoID0gNDAwLCBhbnRpYWxpYXMgPSAic3VicGl4ZWwiKQpwcmludChwbHR1bWFwY29uZCkKZGV2Lm9mZigpCmBgYAoKVG9wIEdPIHRlcm1zIGFuZCBsb2FkIGRhdGEKCmBgYHtyfQojIGxvYWRpbmcgYW5kIHByZXBhcmluZyBkYXRhCmdvX2Vucl9saXN0ID0gcmVhZFJEUyhmaWxlID0gInJlc3VsdHMvY29uZF9lZmZlY3QvZ29fZW5yX2xpc3QuUkRTIikKCmdvX2Vucl9tYWpvciA9IGdvX2Vucl9saXN0JG1ham9yX2N0CmZvcihjYyBpbiBuYW1lcyhnb19lbnJfbWFqb3IpKXsgIyBhZGRpbmcgdGhlIHRlcm1zIGZvciBzdWJzYW1wbGVkIGhlcGF0b2N5dGVzCiAgZm9yKGN0IGluIG5hbWVzKGdvX2Vucl9tYWpvcltbY2NdXSkpewogICAgaWYoY3Q9PSJIZXBhdG9jeXRlcyIpewogICAgICBnb19lbnJfbWFqb3JbW2NjXV1bW2N0XV0gPSBnb19lbnJfbGlzdCRtYWpvcl9jdF9oZXBbW2NjXV0kSGVwYXRvY3l0ZXMKICAgIH0KICAgIGdvX2Vucl9tYWpvcltbY2NdXVtbY3RdXSA9IGdvX2Vucl9tYWpvcltbY2NdXVtbY3RdXVtnb19lbnJfbWFqb3JbW2NjXV1bW2N0XV0kREI9PSJHTyBUZXJtIixdCiAgfQp9CgoKZm9yKGNvbXAgaW4gbmFtZXMoZ29fZW5yX21ham9yKSl7CiAgZm9yKGN0IGluIG5hbWVzKGdvX2Vucl9tYWpvcltbY29tcF1dKSl7CiAgICBzdWJkaXIgPSAiZmlndXJlX3BhbmVscy9maWcyL2dvdGVybXNfY29uZF9mdWxsLyIKICAgIGdvX2Vucl9tYWpvcltbY29tcF1dW1tjdF1dJGdlbmVJRCA9IHVubGlzdChnb19lbnJfbWFqb3JbW2NvbXBdXVtbY3RdXSRnZW5lSUQpCiAgICB3cml0ZS50YWJsZShnb19lbnJfbWFqb3JbW2NvbXBdXVtbY3RdXSwgCiAgICAgICAgICAgICAgICBmaWxlID0gcGFzdGUwKHN1YmRpciwgIkdPVGVybUJQXyIsIGNvbXAsICJfIiwgY3QsICIuY3N2IiksIAogICAgICAgICAgICAgICAgY29sLm5hbWVzID0gVCwgcm93Lm5hbWVzID0gRiwgcXVvdGUgPSBGLCBzZXAgPSAiLCIpCiAgfQp9CmBgYAoKUGxvdHRpbmcgR08gVGVybXMgbWl4ZWQgYmV0d2VlbiBjb25kaXRpb25zCgpgYGB7cn0KdGVybXNfbGlzdCA9IGxpc3QoKQpmb3IoY3QgaW4gdW5pcXVlKG5hbWVzKGdvX2Vucl9tYWpvciRoZWFsdGh5X3ZfZW1ib2xpc2VkKSkpewogIGVtYl90ZXJtcyA9IGdvX2Vucl9tYWpvciRoZWFsdGh5X3ZfZW1ib2xpc2VkW1tjdF1dWyxjKDIsNyw4LDExKV0KICBlbWJfdGVybXMgPSBlbWJfdGVybXNbZW1iX3Rlcm1zJGNvbmQhPSJoZWFsdGh5IixdCiAgcmVnX3Rlcm1zID0gZ29fZW5yX21ham9yJGhlYWx0aHlfdl9yZWdlbmVyYXRpbmdbW2N0XV1bLGMoMiw3LDgsMTEpXQogIHJlZ190ZXJtcyA9IHJlZ190ZXJtc1tyZWdfdGVybXMkY29uZCE9ImhlYWx0aHkiLF0KICBib3RoX3Rlcm1zID0gbWVyZ2UoZW1iX3Rlcm1zLCByZWdfdGVybXMsIGJ5ID0gMSwgYWxsID0gVClbLC1jKDQsNyldCiAgY29sbmFtZXMoYm90aF90ZXJtcylbMjo1XSA9IGMoInF2YWxfZW1ib2xpemVkIiwgImdlbmVzX2VtYm9saXplZCIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJxdmFsX3JlZ2VuZXJhdGluZyIsICJnZW5lc19yZWdlbmVyYXRpbmciKQogIGJvdGhfdGVybXMkcXZhbF9lbWJvbGl6ZWRbaXMubmEoYm90aF90ZXJtcyRxdmFsX2VtYm9saXplZCldID0gMQogIGJvdGhfdGVybXMkcXZhbF9yZWdlbmVyYXRpbmdbaXMubmEoYm90aF90ZXJtcyRxdmFsX3JlZ2VuZXJhdGluZyldID0gMQogIGJvdGhfdGVybXMkZ2VuZXNfZW1ib2xpemVkW2lzLm5hKGJvdGhfdGVybXMkZ2VuZXNfZW1ib2xpemVkKV0gPSAiIgogIGJvdGhfdGVybXMkZ2VuZXNfcmVnZW5lcmF0aW5nW2lzLm5hKGJvdGhfdGVybXMkZ2VuZXNfcmVnZW5lcmF0aW5nKV0gPSAiIgogIAogIGJvdGhfdGVybXMkZ2VuZXNfYWxsID0gdW5saXN0KGxhcHBseShzdHJzcGxpdChwYXN0ZTAoYm90aF90ZXJtcyRnZW5lc19lbWJvbGl6ZWQsICIvIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJvdGhfdGVybXMkZ2VuZXNfcmVnZW5lcmF0aW5nKSwiLyIpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZnVuY3Rpb24oeCkgcGFzdGUwKHVuaXF1ZSh4W3ghPSIiXSksIGNvbGxhcHNlID0gIi8iKSkpCiAgCiAgYm90aF90ZXJtcyA9IGJvdGhfdGVybXNbYm90aF90ZXJtcyRxdmFsX2VtYm9saXplZDw9MC4wNSB8IGJvdGhfdGVybXMkcXZhbF9yZWdlbmVyYXRpbmc8PTAuMDUsXQogIAogIGJvdGhfdGVybXNfdG9wID0gZ2V0VG9wVGVybXNQYWlyZWQoYm90aF90ZXJtcywgbmNsID0gMTIsIG50ID0gMSkKICB0ZXJtc19saXN0W1tjdF1dID0gYm90aF90ZXJtc190b3AKfQoKcGx0X2xpc3QgPSBsaXN0KCkKZm9yKGN0IGluIG5hbWVzKHRlcm1zX2xpc3QpKXsKICBzdW1fZGYgPSB0ZXJtc19saXN0W1tjdF1dWyxjKDE6Myw3KV0KICBzdW1fZGYkRGVzY3JpcHRpb24gPSBicmVha1N0cihhcy5jaGFyYWN0ZXIoc3VtX2RmJERlc2NyaXB0aW9uKSwgbiA9IDMwKQogIHN1bV9kZiRxdmFsX21heFtzdW1fZGYkcXZhbF9lbWJvbGl6ZWQ+c3VtX2RmJHF2YWxfcmVnZW5lcmF0aW5nXSA9IDEtc3VtX2RmJHF2YWxfbWF4W3N1bV9kZiRxdmFsX2VtYm9saXplZD5zdW1fZGYkcXZhbF9yZWdlbmVyYXRpbmddCiAgcGxvdF9kZiA9IHJlc2hhcGUyOjptZWx0KHN1bV9kZlssMTozXSkKICBwbG90X2RmJERlc2NyaXB0aW9uID0gZmFjdG9yKHBsb3RfZGYkRGVzY3JpcHRpb24sIGxldmVscyA9IHN1bV9kZiREZXNjcmlwdGlvbltvcmRlcihzdW1fZGYkcXZhbF9tYXgpXSkKICBwbG90X2RmJHZhcmlhYmxlID0gdW5saXN0KGxhcHBseShzdHJzcGxpdChhcy5jaGFyYWN0ZXIocGxvdF9kZiR2YXJpYWJsZSksICJfIiksIGZ1bmN0aW9uKHgpIHhbMl0pKQogIAogIHBsdF9saXN0W1tjdF1dID0gZ2dwbG90KHBsb3RfZGYsIGFlcyh4ID0gLWxvZzEwKHZhbHVlKSwgeSA9IERlc2NyaXB0aW9uLCBmaWxsID0gdmFyaWFibGUpKSsKICAgIGdlb21fY29sKHBvc2l0aW9uID0gImRvZGdlIikrCiAgICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAtbG9nMTAoMC4wNSksIGxpbmV0eXBlID0gImRhc2hlZCIpKwogICAgc2NhbGVfeF9jb250aW51b3VzKGxpbWl0cyA9IGMoMCwgbWF4KC1sb2cxMChwbG90X2RmJHZhbHVlKSswLjMpKSwgZXhwYW5kID0gYygwLDApKSsKICAgIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGNvbGNvbmQpKwogICAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLAogICAgICAgICAgYXhpcy50aWNrcyA9IGVsZW1lbnRfbGluZSgpKQp9Cgpmb3IobiBpbiBuYW1lcyhwbHRfbGlzdCkpewogIHBkZihwYXN0ZTAoImZpZ3VyZV9wYW5lbHMvZmlnMi9nb3Rlcm1zX2NvbmQvZ290ZXJtc19taXhlZEdPXyIsIG4sICIucGRmIiksIAogICAgICBoZWlnaHQgPSAyLjgsIHdpZHRoID0gMykKICBwcmludChwbHRfbGlzdFtbbl1dKQogIGRldi5vZmYoKQp9Cgpjb3dwbG90OjpwbG90X2dyaWQocGxvdGxpc3QgPSBwbHRfbGlzdCwgbmNvbCA9IDQsIGFsaWduID0gImh2IikKYGBgCgpUb3AgZW5yaWNoZWQgR08gVGVybXMgLSBncm91cCBzaW1pbGFyIHRlcm1zIGFuZCByZXBvcnQgdGhlIHRvcCAxIG9mIGVhY2ggb2YgNSBncm91cHMgZGV0ZWN0ZWQKCmBgYHtyfQpnb3BsdCA9IGxpc3QoKQpnb3RhYiA9IGxpc3QoKQpmb3IoY29tcCBpbiBuYW1lcyhnb19lbnJfbWFqb3IpKXsKICBmb3IoZ3IgaW4gbmFtZXMoZ29fZW5yX21ham9yW1tjb21wXV0pKXsKICAgIGNvbmRzID0gc3Ryc3BsaXQoY29tcCwgIl92XyIpW1sxXV0KICAgIGZvcihjYyBpbiBjb25kcyl7CiAgICAgIHN1Yl9kZiA9IGdvX2Vucl9tYWpvcltbY29tcF1dW1tncl1dW2dvX2Vucl9tYWpvcltbY29tcF1dW1tncl1dJERCPT0iR08gVGVybSIgJgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdvX2Vucl9tYWpvcltbY29tcF1dW1tncl1dJHF2YWx1ZTw9MC4wNSAmCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ29fZW5yX21ham9yW1tjb21wXV1bW2dyXV0kY29uZD09Y2MsXQogICAgICBpZihucm93KHN1Yl9kZik+MCl7CiAgICAgICAgc3ViX2RmID0gZ2V0VG9wVGVybXMoc3ViX2RmLCBuY2wgPSA1LCBudCA9IDEpCiAgICAgICAgc3ViX2RmID0gc3ViX2RmW29yZGVyKHN1Yl9kZiRxdmFsdWUsIGRlY3JlYXNpbmcgPSBGKSxdCiAgICAgICAgbCA9IGlmZWxzZShucm93KHN1Yl9kZik+MTAsIDEwLCBucm93KHN1Yl9kZikpCiAgICAgICAgc3ViX2RmID0gc3ViX2RmWzE6bCxdCiAgICAgICAgc3ViX2RmJGdlbmVJRCA9IHVubGlzdChzdWJfZGYkZ2VuZUlEKQogICAgICAgIHN1Yl9kZiREZXNjcmlwdGlvbiA9IGJyZWFrU3RyKGFzLmNoYXJhY3RlcihzdWJfZGYkRGVzY3JpcHRpb24pLCAzMCkKICAgICAgICBzdWJfZGYkRGVzY3JpcHRpb24gPSBmYWN0b3Ioc3ViX2RmJERlc2NyaXB0aW9uLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGV2ZWxzID0gcmV2KGFzLmNoYXJhY3RlcihzdWJfZGYkRGVzY3JpcHRpb24pKSkKICAgICAgICAKICAgICAgICBnb3BsdFtbcGFzdGUwKGNvbXAsICJfXyIsIGdyLCAiX18iLCBjYyldXSA9IGdncGxvdChzdWJfZGYsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFlcyh4ID0gLWxvZzEwKHF2YWx1ZSksIHkgPSBEZXNjcmlwdGlvbikpKwogICAgICAgICAgZ2VvbV9jb2woKSsKICAgICAgICAgIHNjYWxlX3hfY29udGludW91cyhleHBhbmQgPSBjKDAsMCksIGxpbWl0cyA9IGMoMCwgbWF4KC1sb2cxMChzdWJfZGYkcXZhbHVlKSkrMC4yNSkpKwogICAgICAgICAgbGFicyh5ID0gIkdPIFRlcm0gRGVzY3JpcHRpb24iLCB0aXRsZSA9IHBhc3RlMChjYywgIiB2cyAiLCBjb25kc1tjb25kcyE9Y2NdKSkrCiAgICAgICAgICB0aGVtZShheGlzLnRpY2tzLnggPSBlbGVtZW50X2xpbmUoKSwKICAgICAgICAgICAgICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMSwgdmp1c3QgPSAwLjUsIGxpbmVoZWlnaHQgPSAwLjc1LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2l6ZSA9IDcpLAogICAgICAgICAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTAsIGhqdXN0ID0gMCksCiAgICAgICAgICAgICAgICBwbG90LnRpdGxlLnBvc2l0aW9uID0gInBsb3QiKQogICAgICAgIGdvdGFiW1twYXN0ZTAoY29tcCwgIl9fIiwgZ3IsICJfXyIsIGNjKV1dID0gc3ViX2RmCiAgICAgIH0KICAgIH0KICB9Cn0KZm9yKG4gaW4gbmFtZXMoZ29wbHQpKXsKICBwZGYocGFzdGUwKCJmaWd1cmVfcGFuZWxzL2ZpZzIvZ290ZXJtc19jb25kL2dvdGVybXNfZmlsdEdPXyIsIG4sICIucGRmIiksIAogICAgICBoZWlnaHQgPSAyLCB3aWR0aCA9IDMpCiAgcHJpbnQoZ29wbHRbW25dXSkKICBkZXYub2ZmKCkKICAKICB3cml0ZS5jc3YoZ290YWJbW25dXSwgZmlsZSA9IHBhc3RlMCgiZmlndXJlX3BhbmVscy9maWcyL2dvdGVybXNfY29uZC9nb3Rlcm1zX2ZpbHRHT18iLCBuLCAiLmNzdiIpLAogICAgICAgICAgICByb3cubmFtZXMgPSBGLCBxdW90ZSA9IEYpCn0KYGBgCgpERSBiZXR3ZWVuIGNvbmRpdGlvbnMgZm9yIGNlbGwgdHlwZXMKCmBgYHtyfQpmaWx0X2NvbXBzID0gcmVhZFJEUyhmaWxlID0gInJlc3VsdHMvY29uZF9lZmZlY3QvYWxsX2ZpbHRfY29uZF9jb21wcy5SRFMiKQoKZm9yKGNvbXAgaW4gbmFtZXMoZmlsdF9jb21wcyRtYWpvcl9jdCkpewogIHN1YmRpciA9ICJmaWd1cmVfcGFuZWxzL2ZpZzIvREVfdGFibGVzLyIKICBkZV9kZiA9IGZpbHRfY29tcHMkbWFqb3JfY3RbW2NvbXBdXQogIGRlX2RmID0gZGVfZGZbZGVfZGYkY2VsbHR5cGUhPSJIZXBhdG9jeXRlcyIsXQogIGRlX2RmID0gcmJpbmQoZGVfZGYsIGZpbHRfY29tcHMkbWFqb3JfY3RfaGVwW1tjb21wXV0pCiAgZGVfZGYgPSBkZV9kZltkZV9kZiRwX3ZhbF9hZGo8PTAuMDUsXQogIAogIHdyaXRlLmNzdihkZV9kZltvcmRlcihkZV9kZiRhdmdfbG9nRkMsIGRlY3JlYXNpbmcgPSBUKSxdLCAKICAgICAgICAgICAgZmlsZSA9IHBhc3RlMChzdWJkaXIsICJERWNvbmRfbWFqb3JfY3RfIiwgY29tcCwgIi5jc3YiKSwgCiAgICAgICAgICAgIGNvbC5uYW1lcyA9IFQsIHJvdy5uYW1lcyA9IEYsIHF1b3RlID0gRikKfQoKZm9yKGcgaW4gbmFtZXMoZmlsdF9jb21wcykpewogIGZvcihjb21wIGluIG5hbWVzKGZpbHRfY29tcHNbW2ddXSkpewogICAgc3ViZGlyID0gZmlsZS5wYXRoKCJ0b19zZW5kIiwgZykKICAgIHdyaXRlLmNzdihmaWx0X2NvbXBzW1tnXV1bW2NvbXBdXSwgZmlsZSA9IHBhc3RlMChzdWJkaXIsICIvREVjb25kaXRpb25zXyIsIGNvbXAsICJfIiwgZywgIi5jc3YiKSwgCiAgICAgICAgICAgICAgY29sLm5hbWVzID0gVCwgcm93Lm5hbWVzID0gRiwgcXVvdGUgPSBGKQogIH0KfQpgYGAKCk1ham9yIGNlbGwgdHlwZXMKCmBgYHtyfQpnZW5lc190b19wbG90ID0gbGlzdCgiSGVwYXRvY3l0ZXMiID0gYygiSEFNUCIsICJTQUExIiwgIkZHQSIsICJHMFMyIiwgIlRORlJTRjFBIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkNZUDNBNyIsICJNVDFBIiwgIkREWDIxIiwgIklMMVJBUCIsICJNVDFYIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIk1HTEwiLCAiTUZTRDJBIiwgIkFQT0E0IiwgIklSRjciLCAiQ0VCUEEiKSwgCiAgICAgICAgICAgICAgICAgICAgICAiSW1tdW5lIiA9IGMoIlMxMDBBOSIsICJDRDgxIiwgIkZDR1IxQSIsICJHQlA1IiwgIlJVTlgzIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkNEMzAwRSIsICJNTkRBIiwgIklMMThCUCIsICJJTDRJMSIsICJXREZZNCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlRSREMiLCAiVFJCQzEiLCAiSUZORyIsICJDRDE2MCIsICJJRklUTTEiKSwgCiAgICAgICAgICAgICAgICAgICAgICAiQ2hvbGFuZ2lvY3l0ZXMiID0gYygiQ0NMMiIsICJJUkYxIiwgIktSVDE5IiwgIkNDTDIwIiwgIklDQU0xIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJNQVAzSzEyIiwgIkVQU1RJMSIsICJQNEhBMSIsICJQRUFLMSIsICJTRUMyNEEiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkxDTjIiLCAiUkFNUDEiLCAiSVRHQjQiLCAiQklLIiwgIkNDTDI4IiksIAogICAgICAgICAgICAgICAgICAgICAgIk1lc2VuY2h5bWFsIiA9IGMoKSwgCiAgICAgICAgICAgICAgICAgICAgICAiRW5kb3RoZWxpYWwiID0gYygiU09YMTgiLCAiUExDRzIiLCAiVEZQSTIiLCAiS0xGMiIsICJTVEMxIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJDWFhDNSIsICJOUFIzIiwgIkNESzYiLCAiQURHUkc2IiwgIlBER0ZCIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJSRlBMMSIsICJJVEdCMyIsICJBREFNVFM0IiwgIktMRjEzIiwgIkdQUjE4MiIpKQoKcGx0X2xpc3RfY29uZCA9IGxpc3QoKQpkZl9saXN0X2NvbmQgPSBsaXN0KCkKZm9yKGN0IGluIHVuaXF1ZShmaWx0X2NvbXBzJG1ham9yX2N0JGhlYWx0aHlfdl9lbWJvbGlzZWQkY2VsbHR5cGUpKXsKICBnID0gaWYoY3Q9PSJIZXBhdG9jeXRlcyIpICJtYWpvcl9jdF9oZXAiIGVsc2UgIm1ham9yX2N0IiAjdXNlIGNvcnJlY3QgSGVwIERFCiAgCiAgIyBwcmVwYXJlIGRhdGEgZnJhbWUKICBwbHRfcmVnID0gZmlsdF9jb21wc1tbZ11dJGhlYWx0aHlfdl9yZWdlbmVyYXRpbmdbLGMoMSwzLDQsNSldCiAgcGx0X3JlZyA9IHVuaXF1ZShwbHRfcmVnW3BsdF9yZWckY2VsbHR5cGU9PWN0LF0pCiAgcGx0X2VtYiA9IGZpbHRfY29tcHNbW2ddXSRoZWFsdGh5X3ZfZW1ib2xpc2VkWyxjKDEsMyw0LDUpXQogIHBsdF9lbWIgPSB1bmlxdWUocGx0X2VtYltwbHRfZW1iJGNlbGx0eXBlPT1jdCxdKQogIHJvd25hbWVzKHBsdF9yZWcpID0gcGx0X3JlZyRnZW5lCiAgcm93bmFtZXMocGx0X2VtYikgPSBwbHRfZW1iJGdlbmUKICAKICAjIGFkZCBGQy9wdmFsIGZvciBnZW5lcyB0aGF0IGFyZSBub3QgaW4gY29tbW9uCiAgcGx0X2RmID0gbWVyZ2UocGx0X2VtYiwgcGx0X3JlZywgYnkgPSAwLCBhbGwgPSBUKQogIHJvd25hbWVzKHBsdF9kZikgPSBwbHRfZGZbLDFdCiAgcGx0X2RmID0gcGx0X2RmWywtYygxLDMsNiw3KV0KICBjb2xuYW1lcyhwbHRfZGYpID0gYygiZ2VuZSIsICJGQ19lbWIiLCAicHZhbF9lbWIiLCAiRkNfcmVnIiwgInB2YWxfcmVnIikKICBwbHRfZGYkZ2VuZSA9IHJvd25hbWVzKHBsdF9kZikKICBwbHRfZGYkRkNfZW1iW2lzLm5hKHBsdF9kZiRGQ19lbWIpXSA9IDAKICBwbHRfZGYkRkNfcmVnW2lzLm5hKHBsdF9kZiRGQ19yZWcpXSA9IDAKICBwbHRfZGYkcHZhbF9lbWJbaXMubmEocGx0X2RmJHB2YWxfZW1iKV0gPSAxCiAgcGx0X2RmJHB2YWxfcmVnW2lzLm5hKHBsdF9kZiRwdmFsX3JlZyldID0gMQogIAogICMgY29uZGl0aW9uIGxhYmVscwogIHBsdF9kZiRjb25kID0gaWZlbHNlKHBsdF9kZiRGQ19lbWI8PSgtMC4yKSAmIHBsdF9kZiRwdmFsX2VtYjw9MC4wNSAmIHBsdF9kZiRGQ19yZWc+PTAsICJlbWJvbGlzZWQiLAogICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShwbHRfZGYkRkNfcmVnPD0oLTAuMikgJiBwbHRfZGYkcHZhbF9yZWc8PTAuMDUgJiBwbHRfZGYkRkNfZW1iPj0wLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicmVnZW5lcmF0aW5nIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKHBsdF9kZiRGQ19yZWc8PSgtMC4yKSAmIHBsdF9kZiRwdmFsX3JlZzw9MC4wNSAmIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwbHRfZGYkRkNfZW1iPD0oLTAuMikgJiBwbHRfZGYkcHZhbF9lbWI8PTAuMDUsICJib3RoIiwib3RoZXIiKSkpCiAgcGx0X2RmJGNvbmQgPSBmYWN0b3IocGx0X2RmJGNvbmQsIGxldmVscyA9IGMoImJvdGgiLCAiZW1ib2xpc2VkIiwgInJlZ2VuZXJhdGluZyIsICJvdGhlciIpKQogIHBsdF9kZiA9IHBsdF9kZltvcmRlcihwbHRfZGYkY29uZCwgZGVjcmVhc2luZyA9IFQpLF0KICAKICAjIGdlbmVzIHRvIHBsb3QKICBiX2dfcGx0ID0gZ2VuZXNfdG9fcGxvdFtbY3RdXVsxOjVdCiAgZW1iX2dfcGx0ID0gZ2VuZXNfdG9fcGxvdFtbY3RdXVs2OjEwXQogIHJlZ19nX3BsdCA9IGdlbmVzX3RvX3Bsb3RbW2N0XV1bMTE6MTVdCiAgCiAgY29scyA9IGMoImJvdGgiID0gIiNDNTQ2MzUiLCAicmVnZW5lcmF0aW5nIiA9ICJzYWxtb24iLCAiZW1ib2xpc2VkIiA9ICJkYXJrcmVkIiwgIm90aGVyIiA9ICJncmV5ODUiKQogIHBsdCA9IGdncGxvdChwbHRfZGYsIGFlcyh4ID0gRkNfZW1iLCB5ID0gRkNfcmVnLCBjb2xvdXIgPSBjb25kKSkrCiAgICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAwKSsKICAgIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDApKwogICAgZ2VvbV9wb2ludCgpKwogICAgZ2VvbV9sYWJlbF9yZXBlbChkYXRhID0gcGx0X2RmW3BsdF9kZiRnZW5lICVpbiUgYyhlbWJfZ19wbHQsIHJlZ19nX3BsdCwgYl9nX3BsdCksXSwgCiAgICAgICAgICAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMobGFiZWwgPSBnZW5lKSwgc2hvdy5sZWdlbmQgPSBGLCBtaW4uc2VnbWVudC5sZW5ndGggPSAwLCAKICAgICAgICAgICAgICAgICAgICAgc2l6ZSA9IDIuNzUsIGxhYmVsLnBhZGRpbmcgPSAwLjE1KSsKICAgIHNjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzID0gY29scykrCiAgICBsYWJzKHRpdGxlID0gY3QsIHggPSAibG9nRkMoaGVhbHRoeSB2cyBlbWJvbGlzZWQpIiwgY29sb3VyID0gIkNvbmRpdGlvbiIsCiAgICAgICAgIHkgPSAibG9nRkMoaGVhbHRoeSB2cyByZWdlbmVyYXRpbmcpIikrCiAgICB0aGVtZV9idygpKwogICAgdGhlbWUoYXhpcy50ZXh0ID0gZWxlbWVudF90ZXh0KGNvbG91ciA9ICJibGFjayIpLAogICAgICAgICAgYXNwZWN0LnJhdGlvID0gMSkKICAKICBwbHRfbGlzdF9jb25kW1tjdF1dID0gcGx0Cn0KCnBkZigiZmlndXJlX3BhbmVscy9maWcyL0RFX2NvbmRfbWFqb3JfY2VsbHR5cGVzLnBkZiIsIGhlaWdodCA9IDUsIHdpZHRoID0gNiwgdXNlRGluZ2JhdHMgPSBGKQpwcmludChwbHRfbGlzdF9jb25kKQpkZXYub2ZmKCkKcGRmKCJmaWd1cmVfcGFuZWxzL2ZpZzIvREVfY29uZF9tYWpvcl9jZWxsdHlwZXNfbm9MZWcucGRmIiwgaGVpZ2h0ID0gNSwgd2lkdGggPSA2LCB1c2VEaW5nYmF0cyA9IEYpCnBsdF9saXN0X2NvbmQgPSBsYXBwbHkocGx0X2xpc3RfY29uZCwgZnVuY3Rpb24oeCkgeCt0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpKQpwcmludChwbHRfbGlzdF9jb25kKQpkZXYub2ZmKCkKYGBgCgpBbGwgY2VsbCB0eXBlcwoKYGBge3J9CnBsdF9saXN0X2NvbmQgPSBsaXN0KCkKZGZfbGlzdF9jb25kID0gbGlzdCgpCmZvcihjdCBpbiB1bmlxdWUoZmlsdF9jb21wcyRjZWxsX3R5cGUkaGVhbHRoeV92X2VtYm9saXNlZCRjZWxsdHlwZSkpewogIGcgPSBpZihjdD09IkhlcGF0b2N5dGVzIikgImNlbGxfdHlwZV9oZXAiIGVsc2UgImNlbGxfdHlwZSIgI3VzZSBjb3JyZWN0IEhlcCBERQogIAogICMgcHJlcGFyZSBkYXRhIGZyYW1lCiAgcGx0X3JlZyA9IGZpbHRfY29tcHNbW2ddXSRoZWFsdGh5X3ZfcmVnZW5lcmF0aW5nWyxjKDEsMyw0LDUpXQogIHBsdF9yZWcgPSB1bmlxdWUocGx0X3JlZ1twbHRfcmVnJGNlbGx0eXBlPT1jdCxdKQogIHBsdF9lbWIgPSBmaWx0X2NvbXBzW1tnXV0kaGVhbHRoeV92X2VtYm9saXNlZFssYygxLDMsNCw1KV0KICBwbHRfZW1iID0gdW5pcXVlKHBsdF9lbWJbcGx0X2VtYiRjZWxsdHlwZT09Y3QsXSkKICByb3duYW1lcyhwbHRfcmVnKSA9IHBsdF9yZWckZ2VuZQogIHJvd25hbWVzKHBsdF9lbWIpID0gcGx0X2VtYiRnZW5lCiAgCiAgIyBhZGQgRkMvcHZhbCBmb3IgZ2VuZXMgdGhhdCBhcmUgbm90IGluIGNvbW1vbgogIHBsdF9kZiA9IG1lcmdlKHBsdF9lbWIsIHBsdF9yZWcsIGJ5ID0gMCwgYWxsID0gVCkKICByb3duYW1lcyhwbHRfZGYpID0gcGx0X2RmWywxXQogIHBsdF9kZiA9IHBsdF9kZlssLWMoMSwzLDYsNyldCiAgY29sbmFtZXMocGx0X2RmKSA9IGMoImdlbmUiLCAiRkNfZW1iIiwgInB2YWxfZW1iIiwgIkZDX3JlZyIsICJwdmFsX3JlZyIpCiAgcGx0X2RmJGdlbmUgPSByb3duYW1lcyhwbHRfZGYpCiAgcGx0X2RmJEZDX2VtYltpcy5uYShwbHRfZGYkRkNfZW1iKV0gPSAwCiAgcGx0X2RmJEZDX3JlZ1tpcy5uYShwbHRfZGYkRkNfcmVnKV0gPSAwCiAgcGx0X2RmJHB2YWxfZW1iW2lzLm5hKHBsdF9kZiRwdmFsX2VtYildID0gMQogIHBsdF9kZiRwdmFsX3JlZ1tpcy5uYShwbHRfZGYkcHZhbF9yZWcpXSA9IDEKICAKICAjIGNvbmRpdGlvbiBsYWJlbHMKICBwbHRfZGYkY29uZCA9IGlmZWxzZShwbHRfZGYkRkNfZW1iPD0oLTAuMikgJiBwbHRfZGYkcHZhbF9lbWI8PTAuMDUgJiBwbHRfZGYkRkNfcmVnPj0wLCAiZW1ib2xpc2VkIiwKICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UocGx0X2RmJEZDX3JlZzw9KC0wLjIpICYgcGx0X2RmJHB2YWxfcmVnPD0wLjA1ICYgcGx0X2RmJEZDX2VtYj49MCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInJlZ2VuZXJhdGluZyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShwbHRfZGYkRkNfcmVnPD0oLTAuMikgJiBwbHRfZGYkcHZhbF9yZWc8PTAuMDUgJiAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGx0X2RmJEZDX2VtYjw9KC0wLjIpICYgcGx0X2RmJHB2YWxfZW1iPD0wLjA1LCAiYm90aCIsIm90aGVyIikpKQogIHBsdF9kZiRjb25kID0gZmFjdG9yKHBsdF9kZiRjb25kLCBsZXZlbHMgPSBjKCJib3RoIiwgImVtYm9saXNlZCIsICJyZWdlbmVyYXRpbmciLCAib3RoZXIiKSkKICBwbHRfZGYgPSBwbHRfZGZbb3JkZXIocGx0X2RmJGNvbmQsIGRlY3JlYXNpbmcgPSBUKSxdCiAgCiAgIyBnZW5lcyB0byBwbG90CiAgb3JkID0gb3JkZXIocGx0X2RmJEZDX2VtYitwbHRfZGYkRkNfcmVnLCBkZWNyZWFzaW5nID0gRikKICBiX2dfcGx0ID0gcGx0X2RmJGdlbmVbb3JkXVtwbHRfZGYkY29uZFtvcmRdPT0iYm90aCIgJiBwbHRfZGYkcHZhbF9lbWJbb3JkXTw9MC4wNSAmIHBsdF9kZiRwdmFsX3JlZ1tvcmRdPD0wLjA1XVsxOjVdCiAgb3JkID0gb3JkZXIocGx0X2RmJEZDX2VtYiwgZGVjcmVhc2luZyA9IEYpCiAgZW1iX2dfcGx0ID0gcGx0X2RmJGdlbmVbb3JkXVtwbHRfZGYkY29uZFtvcmRdPT0iZW1ib2xpc2VkIiAmIHBsdF9kZiRwdmFsX2VtYltvcmRdPD0wLjA1XVsxOjVdCiAgb3JkID0gb3JkZXIocGx0X2RmJEZDX3JlZywgZGVjcmVhc2luZyA9IEYpCiAgcmVnX2dfcGx0ID0gcGx0X2RmJGdlbmVbb3JkXVtwbHRfZGYkY29uZFtvcmRdPT0icmVnZW5lcmF0aW5nIiAmIHBsdF9kZiRwdmFsX3JlZ1tvcmRdPD0wLjA1XVsxOjVdCiAgCiAgY29scyA9IGMoImJvdGgiID0gIiNDNTQ2MzUiLCAicmVnZW5lcmF0aW5nIiA9ICJzYWxtb24iLCAiZW1ib2xpc2VkIiA9ICJkYXJrcmVkIiwgIm90aGVyIiA9ICJncmV5ODUiKQogIHBsdCA9IGdncGxvdChwbHRfZGYsIGFlcyh4ID0gRkNfZW1iLCB5ID0gRkNfcmVnLCBjb2xvdXIgPSBjb25kKSkrCiAgICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAwKSsKICAgIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDApKwogICAgZ2VvbV9wb2ludCgpKwogICAgZ2VvbV9sYWJlbF9yZXBlbChkYXRhID0gcGx0X2RmW3BsdF9kZiRnZW5lICVpbiUgYyhlbWJfZ19wbHQsIHJlZ19nX3BsdCwgYl9nX3BsdCksXSwgCiAgICAgICAgICAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMobGFiZWwgPSBnZW5lKSwgc2hvdy5sZWdlbmQgPSBGLCBtaW4uc2VnbWVudC5sZW5ndGggPSAwLCAKICAgICAgICAgICAgICAgICAgICAgc2l6ZSA9IDIuNzUsIGxhYmVsLnBhZGRpbmcgPSAwLjE1KSsKICAgIHNjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzID0gY29scykrCiAgICBsYWJzKHRpdGxlID0gY3QsIHggPSAibG9nRkMoaGVhbHRoeSB2cyBlbWJvbGlzZWQpIiwgY29sb3VyID0gIkNvbmRpdGlvbiIsCiAgICAgICAgIHkgPSAibG9nRkMoaGVhbHRoeSB2cyByZWdlbmVyYXRpbmcpIikrCiAgICB0aGVtZV9idygpKwogICAgdGhlbWUoYXhpcy50ZXh0ID0gZWxlbWVudF90ZXh0KGNvbG91ciA9ICJibGFjayIpLAogICAgICAgICAgYXNwZWN0LnJhdGlvID0gMSkKICAKICBwbHRfbGlzdF9jb25kW1tjdF1dID0gcGx0Cn0KCnBkZigiZmlndXJlX3BhbmVscy9maWcyL0RFX2NvbmRfYWxsX2NlbGx0eXBlcy5wZGYiLCBoZWlnaHQgPSA1LCB3aWR0aCA9IDYsIHVzZURpbmdiYXRzID0gRikKcHJpbnQocGx0X2xpc3RfY29uZCkKZGV2Lm9mZigpCnBkZigiZmlndXJlX3BhbmVscy9maWcyL0RFX2NvbmRfYWxsX2NlbGx0eXBlc19ub0xlZy5wZGYiLCBoZWlnaHQgPSA1LCB3aWR0aCA9IDYsIHVzZURpbmdiYXRzID0gRikKcGx0X2xpc3RfY29uZCA9IGxhcHBseShwbHRfbGlzdF9jb25kLCBmdW5jdGlvbih4KSB4K3RoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikpCnByaW50KHBsdF9saXN0X2NvbmQpCmRldi5vZmYoKQpgYGAKCkNvdW50IERFIGdlbmVzIHBlciBjZWxsIHR5cGUgaW4gY29uZGl0aW9ucyAtIG1ham9yIGNlbGwgdHlwZXMKCmBgYHtyfQpkZV9kZiA9IGZpbHRfY29tcHMkbWFqb3JfY3QkaGVhbHRoeV92X2VtYm9saXNlZApkZV9kZiA9IGRlX2RmW2RlX2RmJHBfdmFsX2Fkajw9MC4wNSAmIGFicyhkZV9kZiRhdmdfbG9nRkMpPj0wLjIsXQpnZW5lc191cCA9IHRhcHBseShkZV9kZiRnZW5lW2RlX2RmJGF2Z19sb2dGQz4wXSwgZGVfZGYkY2VsbHR5cGVbZGVfZGYkYXZnX2xvZ0ZDPjBdLCBsaXN0KQpnZW5lc19kbiA9IHRhcHBseShkZV9kZiRnZW5lW2RlX2RmJGF2Z19sb2dGQzwwXSwgZGVfZGYkY2VsbHR5cGVbZGVfZGYkYXZnX2xvZ0ZDPDBdLCBsaXN0KQpkZV9oZXAgPSBmaWx0X2NvbXBzJG1ham9yX2N0X2hlcCRoZWFsdGh5X3ZfZW1ib2xpc2VkCmdlbmVzX3VwJEhlcGF0b2N5dGVzID0gZGVfaGVwJGdlbmVbZGVfaGVwJGF2Z19sb2dGQz49MC4yICYgZGVfaGVwJHBfdmFsX2Fkajw9MC4wNV0KZ2VuZXNfZG4kSGVwYXRvY3l0ZXMgPSBkZV9oZXAkZ2VuZVtkZV9oZXAkYXZnX2xvZ0ZDPD0oLTAuMikgJiBkZV9oZXAkcF92YWxfYWRqPD0wLjA1XQpkZV9kZl9nID0gcmJpbmQocmVzaGFwZTI6Om1lbHQoZ2VuZXNfdXApLCByZXNoYXBlMjo6bWVsdChnZW5lc19kbikpCmRlX2RmX2ckZGVkaXIgPSBjKHJlcCgiaGlnaGVyIGluIGhlYWx0aHkiLCBsZW5ndGgodW5saXN0KGdlbmVzX3VwKSkpLCAKICAgICAgICAgICAgICAgICAgcmVwKCJoaWdoZXIgaW4gZW1ib2xpc2VkIiwgbGVuZ3RoKHVubGlzdChnZW5lc19kbikpKSkKCmRlX2RmX3IgPSBmaWx0X2NvbXBzJG1ham9yX2N0JGhlYWx0aHlfdl9yZWdlbmVyYXRpbmcKZGVfZGZfciA9IGRlX2RmX3JbZGVfZGZfciRwX3ZhbF9hZGo8PTAuMDUgJiBhYnMoZGVfZGZfciRhdmdfbG9nRkMpPj0wLjIsXQpnZW5lc191cCA9IHRhcHBseShkZV9kZl9yJGdlbmVbZGVfZGZfciRhdmdfbG9nRkM+MF0sIGRlX2RmX3IkY2VsbHR5cGVbZGVfZGZfciRhdmdfbG9nRkM+MF0sIGxpc3QpCmdlbmVzX2RuID0gdGFwcGx5KGRlX2RmX3IkZ2VuZVtkZV9kZl9yJGF2Z19sb2dGQzwwXSwgZGVfZGZfciRjZWxsdHlwZVtkZV9kZl9yJGF2Z19sb2dGQzwwXSwgbGlzdCkKZGVfaGVwID0gZmlsdF9jb21wcyRtYWpvcl9jdF9oZXAkaGVhbHRoeV92X3JlZ2VuZXJhdGluZwpnZW5lc191cCRIZXBhdG9jeXRlcyA9IGRlX2hlcCRnZW5lW2RlX2hlcCRhdmdfbG9nRkM+PTAuMiAmIGRlX2hlcCRwX3ZhbF9hZGo8PTAuMDVdCmdlbmVzX2RuJEhlcGF0b2N5dGVzID0gZGVfaGVwJGdlbmVbZGVfaGVwJGF2Z19sb2dGQzw9KC0wLjIpICYgZGVfaGVwJHBfdmFsX2Fkajw9MC4wNV0KZGVfZGZfcl9nID0gcmJpbmQocmVzaGFwZTI6Om1lbHQoZ2VuZXNfdXApLCByZXNoYXBlMjo6bWVsdChnZW5lc19kbikpCmRlX2RmX3JfZyRkZWRpciA9IGMocmVwKCJoaWdoZXIgaW4gaGVhbHRoeSIsIGxlbmd0aCh1bmxpc3QoZ2VuZXNfdXApKSksIAogICAgICAgICAgICAgICAgICAgIHJlcCgiaGlnaGVyIGluIHJlZ2VuZXJhdGluZyIsIGxlbmd0aCh1bmxpc3QoZ2VuZXNfZG4pKSkpCgoKY291bnRzX2RlID0gcmJpbmQoZGF0YS5mcmFtZSh0YWJsZShkZV9kZl9nJEwxLCBkZV9kZl9nJGRlZGlyKSksIGRhdGEuZnJhbWUodGFibGUoZGVfZGZfcl9nJEwxLCBkZV9kZl9yX2ckZGVkaXIpKSkKY291bnRzX2RlJGNvbXAgPSByZXAoYygiaGVhbHRoeSB2cyBlbWJvbGlzZWQiLCAiaGVhbHRoeSB2cyByZWdlbmVyYXRpbmciKSwgZWFjaCA9IDEwKQpjb3VudHNfZGUkVmFyMiA9IGZhY3Rvcihjb3VudHNfZGUkVmFyMiwgCiAgICAgICAgICAgICAgICAgICAgICAgIGxldmVscyA9IGMoImhpZ2hlciBpbiBoZWFsdGh5IiwgImhpZ2hlciBpbiBlbWJvbGlzZWQiLCAiaGlnaGVyIGluIHJlZ2VuZXJhdGluZyIpKQoKcGx0ID0gZ2dwbG90KGNvdW50c19kZSwgYWVzKHggPSBWYXIxLCB5ID0gRnJlcSwgZmlsbCA9IFZhcjIpKSsKICBmYWNldF93cmFwKH5jb21wLCBucm93ID0gMikrCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygiaGlnaGVyIGluIGhlYWx0aHkiID0gIm9yYW5nZSIsICJoaWdoZXIgaW4gcmVnZW5lcmF0aW5nIiA9ICJzYWxtb24iLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJoaWdoZXIgaW4gZW1ib2xpc2VkIiA9ICJkYXJrcmVkIikpKwogIHNjYWxlX3lfY29udGludW91cyhleHBhbmQgPSBjKDAsMCksIGxpbWl0cyA9IGMoMCwgNDAwMCkpKwogIGxhYnMoZmlsbCA9ICJERSBnZW5lcyIsIHggPSAiQ2VsbCB0eXBlcyIsIHkgPSAiIyBERSBnZW5lcyIpKwogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiKSsKICB0aGVtZV9jbGFzc2ljKCkrCiAgdGhlbWUobGVnZW5kLmp1c3RpZmljYXRpb249YygwLDEpLCBsZWdlbmQucG9zaXRpb249YygwLDEpLAogICAgICAgIGxlZ2VuZC5ib3guYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChjb2xvdXIgPSAidHJhbnNwYXJlbnQiLCBmaWxsID0gInRyYW5zcGFyZW50IiksCiAgICAgICAgbGVnZW5kLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoY29sb3VyID0gInRyYW5zcGFyZW50IiwgZmlsbCA9ICJ0cmFuc3BhcmVudCIpLAogICAgICAgIGxlZ2VuZC5rZXkuc2l6ZSA9IHVuaXQoMC40LCAiY20iKSwKICAgICAgICBheGlzLnRleHQgPSBlbGVtZW50X3RleHQoY29sb3VyID0gImJsYWNrIiksCiAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxLCB2anVzdCA9IDEpKQoKcGRmKCJmaWd1cmVfcGFuZWxzL2ZpZzIvYmFycGxvdF9kZWNvbmRfbWFqb3IucGRmIiwgaGVpZ2h0ID0gNSwgd2lkdGggPSAzLCB1c2VEaW5nYmF0cyA9IEYpCnByaW50KHBsdCkKZGV2Lm9mZigpCnBuZygiZmlndXJlX3BhbmVscy9maWcyL2JhcnBsb3RfZGVjb25kX21ham9yLnBuZyIsIGhlaWdodCA9IDUwMCwgd2lkdGggPSAzNTAsIGFudGlhbGlhcyA9ICJzdWJwaXhlbCIpCnByaW50KHBsdCkKZGV2Lm9mZigpCmBgYAoKQ291bnQgREUgZ2VuZXMgcGVyIGNlbGwgdHlwZSBpbiBjb25kaXRpb25zIC0gYWxsIGNlbGwgdHlwZXMKCmBgYHtyfQpkZV9kZiA9IGZpbHRfY29tcHMkY2VsbF90eXBlX3NpbXAkaGVhbHRoeV92X2VtYm9saXNlZApkZV9kZiA9IGRlX2RmW2RlX2RmJHBfdmFsX2Fkajw9MC4wNSAmIGFicyhkZV9kZiRhdmdfbG9nRkMpPj0wLjIsXQpnZW5lc191cCA9IHRhcHBseShkZV9kZiRnZW5lW2RlX2RmJGF2Z19sb2dGQz4wXSwgZGVfZGYkY2VsbHR5cGVbZGVfZGYkYXZnX2xvZ0ZDPjBdLCBsaXN0KQpnZW5lc19kbiA9IHRhcHBseShkZV9kZiRnZW5lW2RlX2RmJGF2Z19sb2dGQzwwXSwgZGVfZGYkY2VsbHR5cGVbZGVfZGYkYXZnX2xvZ0ZDPDBdLCBsaXN0KQpkZV9oZXAgPSBmaWx0X2NvbXBzJG1ham9yX2N0X2hlcCRoZWFsdGh5X3ZfZW1ib2xpc2VkCmdlbmVzX3VwJEhlcGF0b2N5dGVzID0gZGVfaGVwJGdlbmVbZGVfaGVwJGF2Z19sb2dGQz49MC4yICYgZGVfaGVwJHBfdmFsX2Fkajw9MC4wNV0KZ2VuZXNfZG4kSGVwYXRvY3l0ZXMgPSBkZV9oZXAkZ2VuZVtkZV9oZXAkYXZnX2xvZ0ZDPD0oLTAuMikgJiBkZV9oZXAkcF92YWxfYWRqPD0wLjA1XQpkZV9kZl9nID0gcmJpbmQocmVzaGFwZTI6Om1lbHQoZ2VuZXNfdXApLCByZXNoYXBlMjo6bWVsdChnZW5lc19kbikpCmRlX2RmX2ckZGVkaXIgPSBjKHJlcCgiaGlnaGVyIGluIGhlYWx0aHkiLCBsZW5ndGgodW5saXN0KGdlbmVzX3VwKSkpLCAKICAgICAgICAgICAgICAgICAgcmVwKCJoaWdoZXIgaW4gZW1ib2xpc2VkIiwgbGVuZ3RoKHVubGlzdChnZW5lc19kbikpKSkKCmRlX2RmX3IgPSBmaWx0X2NvbXBzJGNlbGxfdHlwZV9zaW1wJGhlYWx0aHlfdl9yZWdlbmVyYXRpbmcKZGVfZGZfciA9IGRlX2RmX3JbZGVfZGZfciRwX3ZhbF9hZGo8PTAuMDUgJiBhYnMoZGVfZGZfciRhdmdfbG9nRkMpPj0wLjIsXQpnZW5lc191cCA9IHRhcHBseShkZV9kZl9yJGdlbmVbZGVfZGZfciRhdmdfbG9nRkM+MF0sIGRlX2RmX3IkY2VsbHR5cGVbZGVfZGZfciRhdmdfbG9nRkM+MF0sIGxpc3QpCmdlbmVzX2RuID0gdGFwcGx5KGRlX2RmX3IkZ2VuZVtkZV9kZl9yJGF2Z19sb2dGQzwwXSwgZGVfZGZfciRjZWxsdHlwZVtkZV9kZl9yJGF2Z19sb2dGQzwwXSwgbGlzdCkKZGVfaGVwID0gZmlsdF9jb21wcyRtYWpvcl9jdF9oZXAkaGVhbHRoeV92X3JlZ2VuZXJhdGluZwpnZW5lc191cCRIZXBhdG9jeXRlcyA9IGRlX2hlcCRnZW5lW2RlX2hlcCRhdmdfbG9nRkM+PTAuMiAmIGRlX2hlcCRwX3ZhbF9hZGo8PTAuMDVdCmdlbmVzX2RuJEhlcGF0b2N5dGVzID0gZGVfaGVwJGdlbmVbZGVfaGVwJGF2Z19sb2dGQzw9KC0wLjIpICYgZGVfaGVwJHBfdmFsX2Fkajw9MC4wNV0KZGVfZGZfcl9nID0gcmJpbmQocmVzaGFwZTI6Om1lbHQoZ2VuZXNfdXApLCByZXNoYXBlMjo6bWVsdChnZW5lc19kbikpCmRlX2RmX3JfZyRkZWRpciA9IGMocmVwKCJoaWdoZXIgaW4gaGVhbHRoeSIsIGxlbmd0aCh1bmxpc3QoZ2VuZXNfdXApKSksIAogICAgICAgICAgICAgICAgICAgIHJlcCgiaGlnaGVyIGluIHJlZ2VuZXJhdGluZyIsIGxlbmd0aCh1bmxpc3QoZ2VuZXNfZG4pKSkpCgpjb3VudHNfZGUgPSByYmluZChkYXRhLmZyYW1lKHRhYmxlKGRlX2RmX2ckTDEsIGRlX2RmX2ckZGVkaXIpKSwgCiAgICAgICAgICAgICAgICAgIGRhdGEuZnJhbWUodGFibGUoZGVfZGZfcl9nJEwxLCBkZV9kZl9yX2ckZGVkaXIpKSkKY291bnRzX2RlJGNvbXAgPSByZXAoYygiaGVhbHRoeSB2cyBlbWJvbGlzZWQiLCAiaGVhbHRoeSB2cyByZWdlbmVyYXRpbmciKSwgZWFjaCA9IDE0KQpjb3VudHNfZGUkVmFyMiA9IGZhY3Rvcihjb3VudHNfZGUkVmFyMiwgCiAgICAgICAgICAgICAgICAgICAgICAgIGxldmVscyA9IGMoImhpZ2hlciBpbiBoZWFsdGh5IiwgImhpZ2hlciBpbiBlbWJvbGlzZWQiLCAiaGlnaGVyIGluIHJlZ2VuZXJhdGluZyIpKQoKcGx0ID0gZ2dwbG90KGNvdW50c19kZSwgYWVzKHggPSBWYXIxLCB5ID0gRnJlcSwgZmlsbCA9IFZhcjIpKSsKICBmYWNldF93cmFwKH5jb21wKSsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCJoaWdoZXIgaW4gaGVhbHRoeSIgPSAib3JhbmdlIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiaGlnaGVyIGluIHJlZ2VuZXJhdGluZyIgPSAic2FsbW9uIiwgImhpZ2hlciBpbiBlbWJvbGlzZWQiID0gImRhcmtyZWQiKSkrCiAgc2NhbGVfeV9jb250aW51b3VzKGV4cGFuZCA9IGMoMCwwKSwgbGltaXRzID0gYygwLCAzNTAwKSkrCiAgbGFicyhmaWxsID0gIkRFIGdlbmVzIiwgeCA9ICJDZWxsIHR5cGVzIiwgeSA9ICIjIERFIGdlbmVzIikrCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIpKwogIHRoZW1lX2NsYXNzaWMoKSsKICB0aGVtZShsZWdlbmQuanVzdGlmaWNhdGlvbj1jKDAsMSksIGxlZ2VuZC5wb3NpdGlvbj1jKDAsMSksCiAgICAgICAgbGVnZW5kLmJveC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGNvbG91ciA9ICJ0cmFuc3BhcmVudCIsIGZpbGwgPSAidHJhbnNwYXJlbnQiKSwKICAgICAgICBsZWdlbmQuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChjb2xvdXIgPSAidHJhbnNwYXJlbnQiLCBmaWxsID0gInRyYW5zcGFyZW50IiksCiAgICAgICAgbGVnZW5kLmtleS5zaXplID0gdW5pdCgwLjQsICJjbSIpLAogICAgICAgIGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dChjb2xvdXIgPSAiYmxhY2siKSwKICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEsIHZqdXN0ID0gMSkpCgpwZGYoImZpZ3VyZV9wYW5lbHMvZmlnMi9iYXJwbG90X2RlY29uZF9hbGwucGRmIiwgaGVpZ2h0ID0gNCwgd2lkdGggPSA2LCB1c2VEaW5nYmF0cyA9IEYpCnByaW50KHBsdCkKZGV2Lm9mZigpCnBuZygiZmlndXJlX3BhbmVscy9maWcyL2JhcnBsb3RfZGVjb25kX2FsbC5wbmciLCBoZWlnaHQgPSAzNTAsIHdpZHRoID0gNTAwLCBhbnRpYWxpYXMgPSAic3VicGl4ZWwiKQpwcmludChwbHQpCmRldi5vZmYoKQpgYGAKCgojIyBTdXBwbGVtZW50YXJ5CkdlbmUgYW5kIFVNSSBjb3VudHMgcGVyIG1ham9yIGNlbGwgdHlwZSBhbmQgY29uZGl0aW9uCgpgYGB7cn0KcGxvdF9kZiA9IGFsbGNlbGxzX2Nzc0BtZXRhLmRhdGEKcGxvdF9kZiRDb25kaXRpb24gPSBmYWN0b3IocGxvdF9kZiRDb25kaXRpb24sIGxldmVscyA9IGMoImhlYWx0aHkiLCAiZW1ib2xpc2VkIiwgInJlZ2VuZXJhdGluZyIpKQpwbG90X2RmJG1ham9yX2N0ID0gZmFjdG9yKHBsb3RfZGYkbWFqb3JfY3QsIGxldmVscyA9IGMoIkhlcGF0b2N5dGVzIiwgIkVuZG90aGVsaWFsIiwgIkNob2xhbmdpb2N5dGVzIiwgIkltbXVuZSIsICJNZXNlbmNoeW1hbCIpKQoKdmlvX2NvdW50c19jdCA9IGdncGxvdChwbG90X2RmWyFpcy5uYShwbG90X2RmJG1ham9yX2N0KSxdLCAKICAgICAgICAgICAgICAgICAgICAgICBhZXMoeSA9IG5Db3VudF9TQ1QsIHggPSBDb25kaXRpb24sIGZpbGwgPSBDb25kaXRpb24pKSsKICBmYWNldF93cmFwKH5tYWpvcl9jdCwgc2NhbGVzID0gImZyZWVfeCIpKwogIGdlb21fdmlvbGluKCkrCiAgc2NhbGVfeV9sb2cxMChuYW1lID0gIiMgVU1JIChub3JtYWxpc2VkKSIpKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGNvbGNvbmQpKwogIHRoZW1lKHBhbmVsLmdyaWQubWFqb3IueSA9IGVsZW1lbnRfbGluZShjb2xvdXIgPSAiZ3JleTg1IiksCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLAogICAgICAgIGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dCgpLAogICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KHNpemUgPSA5KSwKICAgICAgICBheGlzLnRpdGxlLnggPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEwKSwKICAgICAgICBzdHJpcC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSA5KSwKICAgICAgICBzdHJpcC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAidHJhbnNwYXJlbnQiLCBjb2xvdXIgPSAiYmxhY2siLCBzaXplID0gMC45KSkKCnBkZigiZmlndXJlX3BhbmVscy9maWcyL3Zpb2xpbl9uY291bnRzX21ham9yX2NlbGx0eXBlLnBkZiIsIGhlaWdodCA9IDQsIHdpZHRoID0gNywgdXNlRGluZ2JhdHMgPSBGKQpwcmludCh2aW9fY291bnRzX2N0KQpkZXYub2ZmKCkKcG5nKCJmaWd1cmVfcGFuZWxzL2ZpZzIvdmlvbGluX25jb3VudHNfbWFqb3JfY2VsbHR5cGUucG5nIiwgaGVpZ2h0ID0gNDI1LCB3aWR0aCA9IDU1MCwgYW50aWFsaWFzID0gInN1YnBpeGVsIikKcHJpbnQodmlvX2NvdW50c19jdCkKZGV2Lm9mZigpCgp2aW9fY291bnRzX2N0ID0gZ2dwbG90KHBsb3RfZGZbIWlzLm5hKHBsb3RfZGYkbWFqb3JfY3QpLF0sIAogICAgICAgICAgICAgICAgICAgICAgIGFlcyh5ID0gbkZlYXR1cmVfU0NULCB4ID0gQ29uZGl0aW9uLCBmaWxsID0gQ29uZGl0aW9uKSkrCiAgZmFjZXRfd3JhcCh+bWFqb3JfY3QsIHNjYWxlcyA9ICJmcmVlX3giKSsKICBnZW9tX3Zpb2xpbigpKwogIHNjYWxlX3lfbG9nMTAobmFtZSA9ICIjIEdlbmVzIikrCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gY29sY29uZCkrCiAgdGhlbWUocGFuZWwuZ3JpZC5tYWpvci55ID0gZWxlbWVudF9saW5lKGNvbG91ciA9ICJncmV5ODUiKSwKICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAibm9uZSIsCiAgICAgICAgYXhpcy50ZXh0ID0gZWxlbWVudF90ZXh0KCksCiAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoc2l6ZSA9IDkpLAogICAgICAgIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTApLAogICAgICAgIHN0cmlwLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDkpLAogICAgICAgIHN0cmlwLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJ0cmFuc3BhcmVudCIsIGNvbG91ciA9ICJibGFjayIsIHNpemUgPSAwLjkpKQoKcGRmKCJmaWd1cmVfcGFuZWxzL2ZpZzIvdmlvbGluX25nZW5lc19tYWpvcl9jZWxsdHlwZS5wZGYiLCBoZWlnaHQgPSA0LCB3aWR0aCA9IDcsIHVzZURpbmdiYXRzID0gRikKcHJpbnQodmlvX2NvdW50c19jdCkKZGV2Lm9mZigpCnBuZygiZmlndXJlX3BhbmVscy9maWcyL3Zpb2xpbl9uZ2VuZXNfbWFqb3JfY2VsbHR5cGUucG5nIiwgaGVpZ2h0ID0gNDI1LCB3aWR0aCA9IDU1MCwgYW50aWFsaWFzID0gInN1YnBpeGVsIikKcHJpbnQodmlvX2NvdW50c19jdCkKZGV2Lm9mZigpCmBgYAoKblVNSSBpbiBmaWx0ZXJlZCBhbmQga2VwdCBjZWxscwoKYGBge3J9CmNfbWV0YSA9IFJlZHVjZShyYmluZCwgbGFwcGx5KGNvbmRfc3JhdCwgZnVuY3Rpb24oeCkgeEBtZXRhLmRhdGEpKVssYygxMSwxMiwxMywxNCwxNSwxNywyMyldCmhfbWV0YSA9IFJlZHVjZShyYmluZCwgbGFwcGx5KGhlYWx0aHlfc3JhdCwgZnVuY3Rpb24oeCkgeEBtZXRhLmRhdGEpKVssYygxMSwxMiwxMywxNCwxNSwxNywyMyldCmFsbF9tZXRhID0gcmJpbmQoaF9tZXRhLCBjX21ldGEpCgphbGxfbWV0YSRrZWVwX2FsbGZpbHQgPSBmYWN0b3IoYygiTm8iLCAiWWVzIilbYWxsX21ldGEka2VlcF9hbGxmaWx0KzFdLCBsZXZlbHMgPSBjKCJZZXMiLCAiTm8iKSkKYWxsX21ldGEkTmFtZSA9IGZhY3RvcihhbGxfbWV0YSROYW1lLCAKICAgICAgICAgICAgICAgICAgICAgICBsZXZlbHMgPSBwYXN0ZTAoInNjXyIsIGMocGFzdGUwKCJIIiwxOjMpLHBhc3RlMCgiRSIsYygxOjMsNTo3KSkscGFzdGUwKCJSIixjKDE6Myw1OjcpKSkpKQpsZXZlbHMoYWxsX21ldGEkTmFtZSkgPSBwYXN0ZTAoInNjXyIsIGMocGFzdGUwKCJIIiwxOjMpLHBhc3RlMCgiRSIsMTo2KSxwYXN0ZTAoIlIiLDE6NikpKQoKbl9jZWxscyA9IGFsbF9tZXRhICU+JSBjb3VudChOYW1lLCBGcmFjdGlvbiwga2VlcF9hbGxmaWx0KQoKcGx0ID0gZ2dwbG90KGFsbF9tZXRhLCBhZXMoeCA9IEZyYWN0aW9uLCB5ID0gbkNvdW50X1NDVCwgZmlsbCA9IGtlZXBfYWxsZmlsdCwgY29sb3VyID0ga2VlcF9hbGxmaWx0KSkrCiAgZmFjZXRfd3JhcCh+TmFtZSwgc2NhbGVzID0gImZyZWUiLCBucm93ID0gMykrCiAgZ2VvbV92aW9saW4oc2NhbGUgPSAid2lkdGgiKSsKICBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcyA9IGMoIlllcyIgPSAiZ3JleTIwIiwiTm8iID0gImdyZXk4MCIpKSsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCJZZXMiID0gImdyZXkyMCIsIk5vIiA9ICJncmV5ODAiKSkrCiAgc2NhbGVfeV9sb2cxMCgpKwogIGxhYnMoeSA9ICJuVU1JIiwgY29sb3VyID0gImtlZXAiLCBmaWxsID0gImtlZXAiKSsKICB0aGVtZShzdHJpcC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAidHJhbnNwYXJlbnQiLCBjb2xvdXIgPSAiYmxhY2siLCBzaXplID0gMSksCiAgICAgICAgc3RyaXAudGV4dCA9IGVsZW1lbnRfdGV4dChtYXJnaW4gPSBtYXJnaW4oMiwwLDIsMCksIHNpemUgPSA5KSwKICAgICAgICBheGlzLnRpY2tzID0gZWxlbWVudF9saW5lKCksIAogICAgICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemUgPSA2LjUpKQoKcGRmKCJmaWd1cmVfcGFuZWxzL2ZpZzIvZmlsdGVyaW5nX25VTUkucGRmIiwgaGVpZ2h0ID0gMy4zLCB3aWR0aCA9IDcuMSwgdXNlRGluZ2JhdHMgPSBGKQpwcmludChwbHQpCmRldi5vZmYoKQpgYGAKClVNQVAgd2l0aCBoZWFsdGh5IGRvbm9ycyBzcGxpdAoKYGBge3IsIGZpZy5oZWlnaHQ9MiwgZmlnLndpZHRoPTN9CnBsb3RfZGYgPSBkYXRhLmZyYW1lKGFsbGNlbGxzX2Nzc0ByZWR1Y3Rpb25zJHVtYXBfY3NzQGNlbGwuZW1iZWRkaW5ncykKcGxvdF9kZiREb25vciA9IGZhY3RvcihhbGxjZWxsc19jc3NAbWV0YS5kYXRhJE5hbWUpCnBsb3RfZGYkRG9ub3IgPSBwbHlyOjpyZXZhbHVlKHBsb3RfZGYkRG9ub3IsIGMoInNjX0U1IiA9ICJzY19FNCIsICJzY19SNSIgPSAic2NfUjQiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAic2NfRTYiID0gInNjX0U1IiwgInNjX1I2IiA9ICJzY19SNSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInNjX0U3IiA9ICJzY19FNiIsICJzY19SNyIgPSAic2NfUjYiKSkKcGxvdF9kZiREb25vciA9IGZhY3RvcihwbG90X2RmJERvbm9yLCBsZXZlbHMgPSBjKCJzY19IMSIsICJzY19IMiIsICJzY19IMyIsICJzY19FMSIsICJzY19SMSIsICJzY19FMiIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInNjX1IyIiwgInNjX0UzIiwgInNjX1IzIiwgInNjX0U0IiwgInNjX1I0IiwgInNjX0U1IiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAic2NfUjUiLCAic2NfRTYiLCAic2NfUjYiKSkKcGxvdF9kZiRDb25kaXRpb24gPSBmYWN0b3IoYWxsY2VsbHNfY3NzQG1ldGEuZGF0YSRDb25kaXRpb24sIAogICAgICAgICAgICAgICAgICAgICAgICAgICBsZXZlbHMgPSBjKCJoZWFsdGh5IiwgImVtYm9saXNlZCIsICJyZWdlbmVyYXRpbmciKSkKcGxvdF9kZiRtYWpvcl9jdCA9IGFsbGNlbGxzX2Nzc0BtZXRhLmRhdGEkbWFqb3JfY3QKcGxvdF9kZiRhbGxjZWxsc19tYWpvciA9IGFsbGNlbGxzX2Nzc0BtZXRhLmRhdGEkYWxsY2VsbHNfbWFqb3IKcGxvdF9kZiRtYWpvcl9jdFtpcy5uYShwbG90X2RmJG1ham9yX2N0KV0gPSBwbG90X2RmJGFsbGNlbGxzX21ham9yW2lzLm5hKHBsb3RfZGYkbWFqb3JfY3QpXQpwbG90X2RmJG1ham9yX2N0W3Bsb3RfZGYkbWFqb3JfY3Q9PSJEaXZpZGluZyBjZWxscyJdID0gIkltbXVuZSIgIyB0aGUgZGV0ZWN0ZWQgZGl2aWRpbmcgY2VsbHMgYXJlIG1vc3RseSAoaWYgbm90IGFsbCkgaW1tdW5lIApwbG90X2RmJG1ham9yX2N0ID0gZmFjdG9yKHBsb3RfZGYkbWFqb3JfY3QsIGxldmVscyA9IGMoIkhlcGF0b2N5dGVzIiwgIkVuZG90aGVsaWFsIiwiSW1tdW5lIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJDaG9sYW5naW9jeXRlcyIsIk1lc2VuY2h5bWFsIiwgIkRvdWJsZXRzIikpCgpwbHQgPSBnZ3Bsb3QocGxvdF9kZltzYW1wbGUoMTpucm93KHBsb3RfZGYpLCBucm93KHBsb3RfZGYpLCByZXBsYWNlID0gRiksXSwgCiAgICAgICAgICAgICBhZXMoeCA9IFVNQVBDU1NfMSwgeSA9IFVNQVBDU1NfMiwgY29sb3VyID0gbWFqb3JfY3QpKSsKICBmYWNldF93cmFwKH5Eb25vciwgZHJvcCA9IFQsIG5yb3cgPSAzLCBuY29sID0gNSkrCiAgZ2VvbV9wb2ludChzaXplID0gMC4wOCkrCiAgZ3VpZGVzKGNvbG91ciA9IGd1aWRlX2xlZ2VuZChvdmVycmlkZS5hZXMgPSBsaXN0KHNpemUgPSAzKSwgdGl0bGUgPSAiRG9ub3JzIikpKwogIHNjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzID0gY29sc21ham9yKSsKICB0aGVtZV9jbGFzc2ljKCkrCiAgdGhfZ2VuKwogIHRoZW1lKGF4aXMubGluZSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRpY2tzID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGl0bGUgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy50ZXh0ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIHN0cmlwLnRleHQueCA9IGVsZW1lbnRfdGV4dChzaXplID0gOCwgbWFyZ2luID0gbWFyZ2luKDAuMDYsMCwwLjA2LDAsICJjbSIpKSwKICAgICAgICBzdHJpcC5iYWNrZ3JvdW5kLnggPSBlbGVtZW50X3JlY3Qoc2l6ZSA9IDAuNSwgY29sb3VyID0gInRyYW5zcGFyZW50IiksCiAgICAgICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMCksCiAgICAgICAgYXNwZWN0LnJhdGlvID0gMSkKCnBkZigiZmlndXJlX3BhbmVscy9maWcyL3VtYXBBbGxfZnJlc2hfZG9ub3JzX3NwbGl0LnBkZiIsIAogICAgdXNlRGluZ2JhdHMgPSBGLCBoZWlnaHQgPSA0LjEsIHdpZHRoID0gNi40KQpwcmludChwbHQpCmRldi5vZmYoKQpwbmcoImZpZ3VyZV9wYW5lbHMvZmlnMi91bWFwQWxsX2ZyZXNoX2Rvbm9yc19zcGxpdC5wbmciLCAKICAgIGhlaWdodD04LCB3aWR0aD0xNSwgdW5pdD0iY20iLCByZXM9NjAwLCBhbnRpYWxpYXMgPSAic3VicGl4ZWwiKQpwcmludChwbHQpCmRldi5vZmYoKQpwZGYoImZpZ3VyZV9wYW5lbHMvZmlnMi91bWFwQWxsX2ZyZXNoX2Rvbm9yc19ub0xlZ19zcGxpdC5wZGYiLCAKICAgIHVzZURpbmdiYXRzID0gRiwgaGVpZ2h0ID0gNC4xLCB3aWR0aCA9IDUuOCkKcHJpbnQocGx0K3RoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikpCmRldi5vZmYoKQpwbmcoImZpZ3VyZV9wYW5lbHMvZmlnMi91bWFwQWxsX2ZyZXNoX2Rvbm9yc19ub0xlZ19zcGxpdC5wbmciLCAKICAgIGhlaWdodD04LCB3aWR0aD0xMSwgdW5pdD0iY20iLCByZXM9NjAwLCBhbnRpYWxpYXMgPSAic3VicGl4ZWwiKQpwcmludChwbHQrdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKSkKZGV2Lm9mZigpCnBkZigiZmlndXJlX3BhbmVscy9maWcyL3VtYXBBbGxfZnJlc2hfZG9ub3JzX3NwbGl0X2NvbmQucGRmIiwgCiAgICB1c2VEaW5nYmF0cyA9IEYsIGhlaWdodCA9IDQuMSwgd2lkdGggPSA2LjQpCnByaW50KHBsdCtmYWNldF93cmFwKENvbmRpdGlvbn5Eb25vciwgZHJvcCA9IFQsIG5yb3cgPSAzLCBuY29sID0gNSkpCmRldi5vZmYoKQpwbmcoImZpZ3VyZV9wYW5lbHMvZmlnMi91bWFwQWxsX2ZyZXNoX2Rvbm9yc19zcGxpdF9jb25kLnBuZyIsIAogICAgaGVpZ2h0PTgsIHdpZHRoPTE1LCB1bml0PSJjbSIsIHJlcz02MDAsIGFudGlhbGlhcyA9ICJzdWJwaXhlbCIpCnByaW50KHBsdCtmYWNldF93cmFwKENvbmRpdGlvbn5Eb25vciwgZHJvcCA9IFQsIG5yb3cgPSAzLCBuY29sID0gNSkpCmRldi5vZmYoKQpgYGAKCgoKIyBGaWd1cmUgMwojIyBNYWluIEZpZ3VyZQpab25hdGlvbiBiZXR3ZWVuIGNvbmRpdGlvbnMKCmBgYHtyfQojIGdlbmUgZXhwcmVzc2lvbgpoZXBfY2VsbHMgPSByZWFkUkRTKGZpbGUgPSAicmVzdWx0cy96b25hdGlvbl9jb25kL2hlcF9jZWxsc196b25hdGlvbl9yYW5rLlJEUyIpCgojIGZpdHRlZCBleHByZXNzaW9uCmhlcF9zaWdfZml0cyA9IHJlYWRSRFMoZmlsZSA9ICJyZXN1bHRzL3pvbmF0aW9uX2NvbmQvaGVwX3NpZ19maXRzLlJEUyIpCmhlcF9maXRzX3F2YWwgPSByZWFkUkRTKGZpbGUgPSAicmVzdWx0cy96b25hdGlvbl9jb25kL2hlcF9maXRzX3F2YWwuUkRTIikKCiMgR08gYW5kIGNsdXN0ZXJzCmhlcF9yZXNfbGlzdCA9IHJlYWRSRFMoZmlsZSA9ICJyZXN1bHRzL3pvbmF0aW9uX2NvbmQvaGVwX2dvdF9jbHVzdGVyaW5nX2xpc3QuUkRTIikKCmdfbGlzdCA9IGMoICMgZW1ib2xpc2VkIGNsdXN0ZXJzCiAgIkNPWDdDIiwgIyBveHlnZW4gdHJhbnNwb3J0IGNoYWluIChhbHNvIGluIHJlZ2VuIDIpCiAgIkNZUDM5QTEiLCAjIHN0ZXJvaWQgbWV0YWJvbGlzbQogICJBUkcxIiwgIyBvcmdhbmljIGFjaWQgY2F0YWJvbGljIHByb2Nlc3MgKGFsc28gaW4gcmVnZW4gMikKICAiUFJPWDEiLCAjIGRldmVsb3BpbmcgbGl2ZXIgbWFya2VyCiAgIkNPUEEiLCAjIHZlc2ljbGUgdHJhZmZpY2tpbmcgKGFsc28gaW4gcmVnZW4gMSkKICAiQ0RIMiIsICMgY2x1c3RlciA0CiAgIkNEMTUxIiwgIyBjbHVzdGVyIDQKICAgICAgICAgICAjIHJlZ2VuZXJhdGluZyBjbHVzdGVycwogICJBR1BBVDIiLCAjIGxpcGlkIG1ldGFib2xpc20KICAiQ09YNkMiLCAjIGVsZWN0cm9uIHRyYW5zcG9ydCBjaGFpbgogICJQVEdSMSIsICMgZmF0dHkgYWNpZCBtZXRhYm9saXNtCiAgIkZPWEEzIiwgIyBsaXZlciBkZXZlbG9wbWVudCAoY2x1c3RlciAxKQogICJGT1hPMSIsICMgY29udHJvbCBvZiBtZXRhYm9saXNtIGFuZCBDQyBhcnJlc3QKICAiQ1lQMkE2IiwgIyBjbHVzdGVyIDQKICAiQ1lQMkI2IiwgIyBjbHVzdGVyIDQKICAiQ1lQNEExMSIsICMgY2x1c3RlciA0CiAgIlNEQzQiLCAjIGNsdXN0ZXIgNAogICJTVEFUMSIsICMgY2x1c3RlciA0CiAgIyBub3JtYWwgem9uYXRpb24KICAiU0FBMSIsICJTQUEyIiwgIkhBTVAiLCAiQzMiLCAiQ1lQMkUxIiwiQ1lQMUEyIiwiSFVMQyIsIkJDSEUiLCJDWVAzQTQiLAogICJDUlAiLCAiU0RTIiwgIkhBTCIsICJJR0ZCUDEiLCAiSUdGQlAyIiwgIkJBQVQiLCAiU0xDTzFCMyIpCmBgYAoKYGBge3J9CmhlcF9kZiA9IGRhdGEuZnJhbWUodmFscyA9IGMoaGVwX2NlbGxzJGhlYWx0aHkkem9uYXRpb25fcHQsIGhlcF9jZWxscyRlbWJvbGlzZWQkem9uYXRpb25fcHQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGhlcF9jZWxscyRyZWdlbmVyYXRpbmckem9uYXRpb25fcHQpLCAKICAgICAgICAgICAgICAgICAgICAgQ29uZGl0aW9uID0gYyhyZXAoImhlYWx0aHkiLCBsZW5ndGgoaGVwX2NlbGxzJGhlYWx0aHkkem9uYXRpb25fcHQpKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVwKCJlbWJvbGlzZWQiLCBsZW5ndGgoaGVwX2NlbGxzJGVtYm9saXNlZCR6b25hdGlvbl9wdCkpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXAoInJlZ2VuZXJhdGluZyIsIGxlbmd0aChoZXBfY2VsbHMkcmVnZW5lcmF0aW5nJHpvbmF0aW9uX3B0KSkpLAogICAgICAgICAgICAgICAgICAgICBEb25vciA9IGMoaGVwX2NlbGxzJGhlYWx0aHkkRG9ub3IsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaGVwX2NlbGxzJGVtYm9saXNlZCREb25vciwgaGVwX2NlbGxzJHJlZ2VuZXJhdGluZyREb25vciksCiAgICAgICAgICAgICAgICAgICAgIGN0ID0gYyhoZXBfY2VsbHMkaGVhbHRoeSRhbGxjZWxsc19zaW1wLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGhlcF9jZWxscyRlbWJvbGlzZWQkYWxsY2VsbHNfc2ltcCwgaGVwX2NlbGxzJHJlZ2VuZXJhdGluZyRhbGxjZWxsc19zaW1wKSkKaGVwX2RmJGJpbnMxMCA9IGN1dChoZXBfZGYkdmFscywgMTApCmhlcF9kZiRDb25kaXRpb24gPSBmYWN0b3IoaGVwX2RmJENvbmRpdGlvbiwgbGV2ZWxzID0gYygiaGVhbHRoeSIsICJlbWJvbGlzZWQiLCAicmVnZW5lcmF0aW5nIikpCmxldmVscyhoZXBfZGYkRG9ub3IpID0gYygic2NfRTEvUjEiLCAic2NfRTIvUjIiLCAic2NfRTMvUjMiLCAic2NfRTQvUjQiLCAic2NfRTUvUjUiLCAic2NfRTYvUjYiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICJzY19IMSIsICJzY19IMiIsICJzY19IMyIpCgpwbHRfZGlzdHMgPSBnZ3Bsb3QoaGVwX2RmLCBhZXMoeCA9IGJpbnMxMCwgZmlsbCA9IENvbmRpdGlvbikpKwogICAgIGZhY2V0X3dyYXAofkNvbmRpdGlvbikrCiAgICAgZ2VvbV9iYXIoKSsKICAgICBsYWJzKHggPSAiem9uYXRpb24gKGJpbm5lZCkiLCB5ID0gIk51bWJlciBvZiBjZWxscyIpKwogICAgIHNjYWxlX3lfY29udGludW91cyhleHBhbmQgPSBjKDAsMCkpKwogICAgIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGNvbGNvbmQpKwogICAgIGNvb3JkX2ZsaXAoKSsKICAgICBndWlkZXMoZmlsbCA9IGd1aWRlX2xlZ2VuZCh0aXRsZS5wb3NpdGlvbiA9ICJsZWZ0IikpKwogICAgIHRoZW1lKGF4aXMudGV4dC55ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgICAgIGxlZ2VuZC50aXRsZS5hbGlnbiA9IDAsCiAgICAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIsCiAgICAgICAgICAgbGVnZW5kLmJveC5tYXJnaW4gPSBtYXJnaW4oMCwwLDAsMCksCiAgICAgICAgICAgbGVnZW5kLmJveC5zcGFjaW5nID0gdW5pdCgwLjA1LCAiY20iKSkKCnBkZigiZmlndXJlX3BhbmVscy9maWczL2hlcF96b25hdGlvbl9jb25kaXRpb25EaXN0LnBkZiIsIGhlaWdodCA9IDIuMywgd2lkdGggPSAzLjYsIHVzZURpbmdiYXRzID0gRikKcHJpbnQocGx0X2Rpc3RzKQpkZXYub2ZmKCkKYGBgCgpEb25vciBkZW5zaXR5IHBlciBjb25kaXRpb24KCmBgYHtyfQpoZXBfZG9uID0gZ2dwbG90KGhlcF9kZiwgYWVzKHggPSB2YWxzLCBjb2xvdXIgPSBEb25vcikpKwogICAgIGZhY2V0X3dyYXAofkNvbmRpdGlvbiwgc2NhbGVzID0gImZyZWVfeSIpKwogICAgIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDApKwogICAgIGdlb21fZGVuc2l0eSgpKwogICAgIGxhYnMoeCA9ICJ6b25hdGlvbiIsIHkgPSAiY2VsbCBkZW5zaXR5IikrCiAgICAgc2NhbGVfeV9jb250aW51b3VzKGV4cGFuZCA9IGMoMCwwKSkrCiAgICAgY29vcmRfZmxpcCgpKwogICAgIGd1aWRlcyhjb2xvdXIgPSBndWlkZV9sZWdlbmQodGl0bGUucG9zaXRpb24gPSAibGVmdCIsIG5yb3cgPSAzKSkrCiAgICAgdGhlbWUoYXhpcy50ZXh0LnkgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgICAgYXhpcy50aWNrcy54ID0gZWxlbWVudF9saW5lKCksCiAgICAgICAgICAgc3RyaXAudGV4dCA9IGVsZW1lbnRfdGV4dChtYXJnaW4gPSBtYXJnaW4oMC4wNCwwLDAuMDQsMCwgImNtIiksIHNpemUgPSA3LjUpLAogICAgICAgICAgIGxlZ2VuZC50aXRsZS5hbGlnbiA9IDAsCiAgICAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIsCiAgICAgICAgICAgbGVnZW5kLmJveC5tYXJnaW4gPSBtYXJnaW4oMCwwLDAsMCksCiAgICAgICAgICAgbGVnZW5kLmJveC5zcGFjaW5nID0gdW5pdCgwLjA1LCAiY20iKSkKCnBkZigiZmlndXJlX3BhbmVscy9maWczL2hlcF96b25hdGlvbl9jb25kaXRpb25Eb25vcnMucGRmIiwgaGVpZ2h0ID0gMywgd2lkdGggPSAzLjYsIHVzZURpbmdiYXRzID0gRikKcHJpbnQoaGVwX2RvbikKZGV2Lm9mZigpCmBgYAoKWm9uYXRpb24gZ3JvdXBlZCBieSBkb25vcnMKCmBgYHtyfQpoZXBfZG9uID0gZ2dwbG90KGhlcF9kZiwgYWVzKHggPSB2YWxzLCBjb2xvdXIgPSBDb25kaXRpb24pKSsKICAgICBmYWNldF93cmFwKH5Eb25vciwgc2NhbGVzID0gImZyZWVfeSIpKwogICAgIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDApKwogICAgIGdlb21fZGVuc2l0eSgpKwogICAgIGxhYnMoeCA9ICJ6b25hdGlvbiIsIHkgPSAiY2VsbCBkZW5zaXR5IikrCiAgICAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBjb2xjb25kKSsKICAgICBzY2FsZV95X2NvbnRpbnVvdXMoZXhwYW5kID0gYygwLDApKSsKICAgICBjb29yZF9mbGlwKCkrCiAgICAgZ3VpZGVzKGNvbG91ciA9IGd1aWRlX2xlZ2VuZCh0aXRsZS5wb3NpdGlvbiA9ICJsZWZ0IiwgbmNvbCA9IDMpKSsKICAgICB0aGVtZShheGlzLnRleHQueSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgICBheGlzLnRpY2tzLnggPSBlbGVtZW50X2xpbmUoKSwKICAgICAgICAgICBzdHJpcC50ZXh0ID0gZWxlbWVudF90ZXh0KG1hcmdpbiA9IG1hcmdpbigwLjA0LDAsMC4wNCwwLCAiY20iKSwgc2l6ZSA9IDcuNSksCiAgICAgICAgICAgbGVnZW5kLnRpdGxlLmFsaWduID0gMCwKICAgICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIiwKICAgICAgICAgICBsZWdlbmQuYm94Lm1hcmdpbiA9IG1hcmdpbigwLDAsMCwwKSwKICAgICAgICAgICBsZWdlbmQuYm94LnNwYWNpbmcgPSB1bml0KDAuMDUsICJjbSIpKQoKcGRmKCJmaWd1cmVfcGFuZWxzL2ZpZzMvaGVwX3pvbmF0aW9uX0Rvbm9yc0NvbmQucGRmIiwgaGVpZ2h0ID0gMywgd2lkdGggPSAzLjYsIHVzZURpbmdiYXRzID0gRikKcHJpbnQoaGVwX2RvbikKZGV2Lm9mZigpCmBgYAoKSGVwIGJpbm5lZCB6b25hdGlvbiBub3JtYWxpc2VkIHRvIGhlYWx0aHkKCmBgYHtyfQpoZXBfZGYgPSBkYXRhLmZyYW1lKHZhbHMgPSBjKGhlcF9jZWxscyRoZWFsdGh5JHpvbmF0aW9uX3B0LCBoZXBfY2VsbHMkZW1ib2xpc2VkJHpvbmF0aW9uX3B0LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBoZXBfY2VsbHMkcmVnZW5lcmF0aW5nJHpvbmF0aW9uX3B0KSwgCiAgICAgICAgICAgICAgICAgICAgIENvbmRpdGlvbiA9IGMocmVwKCJoZWFsdGh5IiwgbGVuZ3RoKGhlcF9jZWxscyRoZWFsdGh5JHpvbmF0aW9uX3B0KSksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlcCgiZW1ib2xpc2VkIiwgbGVuZ3RoKGhlcF9jZWxscyRlbWJvbGlzZWQkem9uYXRpb25fcHQpKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVwKCJyZWdlbmVyYXRpbmciLCBsZW5ndGgoaGVwX2NlbGxzJHJlZ2VuZXJhdGluZyR6b25hdGlvbl9wdCkpKSkKaGVwX2RmJGJpbnMxMCA9IGN1dChoZXBfZGYkdmFscywgMTApCmhlcF9kZiRDb25kaXRpb24gPSBmYWN0b3IoaGVwX2RmJENvbmRpdGlvbiwgbGV2ZWxzID0gYygiaGVhbHRoeSIsICJlbWJvbGlzZWQiLCAicmVnZW5lcmF0aW5nIikpCmhlcF9kZiA9IGRhdGEuZnJhbWUodGFibGUoaGVwX2RmJENvbmRpdGlvbiwgaGVwX2RmJGJpbnMxMCkpCmhlcF9kZiA9IGhlcF9kZltvcmRlcihoZXBfZGYkVmFyMSksXQpoZXBfZGYkRnJlcW5vcm0gPSB1bmxpc3QodGFwcGx5KGhlcF9kZiRGcmVxLCBoZXBfZGYkVmFyMSwgZnVuY3Rpb24oeCkgeC9zdW0oeCkpKQpoZXBfZGYkRnJlcW5vcm1faCA9IGhlcF9kZiRGcmVxbm9ybS9tZWFuKGhlcF9kZiRGcmVxbm9ybVtoZXBfZGYkVmFyMT09ImhlYWx0aHkiXSkKCnBsdF9kaXN0cyA9IGdncGxvdChoZXBfZGYsIGFlcyh4ID0gVmFyMiwgZmlsbCA9IFZhcjEsIHkgPSBGcmVxbm9ybV9oKSkrCiAgICAgZmFjZXRfd3JhcCh+VmFyMSkrCiAgICAgZ2VvbV9jb2woKSsKICAgICBsYWJzKHggPSAiem9uYXRpb24gKGJpbm5lZCkiLCB5ID0gIlByb3BvcnRpb24gb2YgY2VsbHMgKGNvbXBhcmVkIHRvIGhlYWx0aHkpIikrCiAgICAgc2NhbGVfeV9jb250aW51b3VzKGV4cGFuZCA9IGMoMCwwKSwgbGFiZWxzID0gYygiMCIsICIwLjUiLCAiMSIsICIxLjUiLCAiMiIsICIyLjUiKSkrCiAgICAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gY29sY29uZCkrCiAgICAgY29vcmRfZmxpcCgpKwogICAgIGd1aWRlcyhmaWxsID0gZ3VpZGVfbGVnZW5kKHRpdGxlLnBvc2l0aW9uID0gImxlZnQiKSkrCiAgICAgdGhlbWUoYXhpcy50ZXh0LnkgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoc2l6ZSA9IDYpLAogICAgICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikKCnBkZigiZmlndXJlX3BhbmVscy9maWczL2hlcF96b25hdGlvbl9jb25kaXRpb25EaXN0X25vcm0ucGRmIiwgCiAgICBoZWlnaHQgPSAyLCB3aWR0aCA9IDMuOCwgdXNlRGluZ2JhdHMgPSBGKQpwcmludChwbHRfZGlzdHMpCmRldi5vZmYoKQpgYGAKClBsb3QgR08gVGVybXMgKGdlbmVyYWwpCgpgYGB7cn0KZ29fdGhlbWUgPSB0aGVtZV9idygpKwogIHRoZW1lKGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dChjb2xvdXIgPSAiYmxhY2siLCBzaXplID0gNy41KSwKICAgICAgICBheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSA4KSwKICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSA5KSwKICAgICAgICBwbG90LnRpdGxlLnBvc2l0aW9uID0gInBsb3QiLAogICAgICAgIHBsb3Quc3VidGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDcuNSksCiAgICAgICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQodmp1c3QgPSAwLjYsIGNvbG91ciA9IGMoImdyZXk0NSIsICJncmV5MTciKSksCiAgICAgICAgcGFuZWwuZ3JpZC5tYWpvci55ID0gZWxlbWVudF9ibGFuaygpKQoKZ29wbHRGdW5jID0gZnVuY3Rpb24ocGxvdF9kZiwgdGl0ID0gIiIsIHN1YnRpdCA9ICIiKXsKICBwbG90X2RmJERlc2NyaXB0aW9uID0gYnJlYWtTdHIocGxvdF9kZiREZXNjcmlwdGlvbiwgMzApCiAgcGxvdF9kZiREZXNjcmlwdGlvbiA9IGZhY3RvcihwbG90X2RmJERlc2NyaXB0aW9uLCBsZXZlbHMgPSByZXYocGxvdF9kZiREZXNjcmlwdGlvbikpCiAgcGxvdF9kZiRmaWxsID0gYXMuY2hhcmFjdGVyKHJlcCgxOjIsIGNlaWxpbmcobnJvdyhwbG90X2RmKS8yKSkpWzE6bnJvdyhwbG90X2RmKV0KICBwbHQgPSBnZ3Bsb3QocGxvdF9kZiwgYWVzKHggPSAtbG9nMTAocXZhbHVlKSwgeSA9IERlc2NyaXB0aW9uLCBmaWxsID0gZmlsbCkpKwogICAgZ2VvbV9jb2woc2hvdy5sZWdlbmQgPSBGKSsKICAgIHNjYWxlX3hfY29udGludW91cyhleHBhbmQgPSBjKDAsMCksIGxpbSA9IGMoMCwgbWF4KC1sb2cxMChwbG90X2RmJHF2YWx1ZSkpKzEpKSsKICAgIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoImdyZXkxNyIsICJncmV5NDUiKSkrCiAgICBsYWJzKHRpdGxlID0gdGl0LCBzdWJ0aXRsZSA9IHN1YnRpdCkrCiAgICBnb190aGVtZQogIHJldHVybihwbHQpCn0KCnBkZigiZmlndXJlX3BhbmVscy9maWczL2hlcF9nb19lbWJfbm90Y29yci5wZGYiLCBoZWlnaHQgPSAzLjIsIHdpZHRoID0gMy42LCB1c2VEaW5nYmF0cyA9IEYpCnByaW50KGdvcGx0RnVuYyhoZXBfcmVzX2xpc3QkZW1ib2xpc2VkJGdvX2NsJGFsbCwgdGl0ID0gIkdPIFRlcm1zIC0gRW1ib2xpc2VkIiwgc3VidGl0ID0gImNvciA8IDAuMyIpKQpkZXYub2ZmKCkKCnBkZigiZmlndXJlX3BhbmVscy9maWczL2hlcF9nb19lbWJfY29yci5wZGYiLCBoZWlnaHQgPSAzLjIsIHdpZHRoID0gMy42LCB1c2VEaW5nYmF0cyA9IEYpCnByaW50KGdvcGx0RnVuYyhoZXBfcmVzX2xpc3QkZW1ib2xpc2VkJGdvX2NsJHBvcywgdGl0ID0gIkdPIFRlcm1zIC0gRW1ib2xpc2VkIiwgc3VidGl0ID0gImNvciA8IDAuMyIpKQpkZXYub2ZmKCkKCnBkZigiZmlndXJlX3BhbmVscy9maWczL2hlcF9nb19yZWdfbm90Y29yci5wZGYiLCBoZWlnaHQgPSAzLjIsIHdpZHRoID0gMy42LCB1c2VEaW5nYmF0cyA9IEYpCnByaW50KGdvcGx0RnVuYyhoZXBfcmVzX2xpc3QkcmVnZW5lcmF0aW5nJGdvX2NsJGFsbCwgdGl0ID0gIkdPIFRlcm1zIC0gUmVnZW5lcmF0aW5nIiwgc3VidGl0ID0gImNvciA+PSAwLjMiKSkKZGV2Lm9mZigpCgpwZGYoImZpZ3VyZV9wYW5lbHMvZmlnMy9oZXBfZ29fcmVnX2NvcnIucGRmIiwgaGVpZ2h0ID0gMy4yLCB3aWR0aCA9IDMuNiwgdXNlRGluZ2JhdHMgPSBGKQpwcmludChnb3BsdEZ1bmMoaGVwX3Jlc19saXN0JHJlZ2VuZXJhdGluZyRnb19jbCRwb3MsIHRpdCA9ICJHTyBUZXJtcyAtIFJlZ2VuZXJhdGluZyIsIHN1YnRpdCA9ICJjb3IgPj0gMC4zIikpCmRldi5vZmYoKQpgYGAKClBsb3QgR08gVGVybXMgKGVhY2ggY2x1c3RlcikKCmBgYHtyfQpwYXRoZ28gPSAiZmlndXJlX3BhbmVscy9maWczL2dvdGVybXNfY2x1c3RlcnMvIgpkaXIuY3JlYXRlKHBhdGhnbywgc2hvd1dhcm5pbmdzID0gRkFMU0UpCgpmb3IoY2MgaW4gbmFtZXMoaGVwX3Jlc19saXN0KSl7CiAgdGl0ID0gaWZlbHNlKGNjPT0iZW1ib2xpc2VkIiwgIkdPIFRlcm1zIC0gRW1ib2xpc2VkIiwgIkdPIFRlcm1zIC0gUmVnZW5lcmF0aW5nIikKICBmb3IobiBpbiAxOjUpewogICAgcGxvdF9kZiA9IGhlcF9yZXNfbGlzdFtbY2NdXSRnb19jbFtbYXMuY2hhcmFjdGVyKG4pXV0KICAgIGlmKG5yb3cocGxvdF9kZik+MCl7CiAgICAgIHBsdCA9IGdvcGx0RnVuYyhwbG90X2RmLCB0aXQgPSB0aXQsIHN1YnRpdCA9IHBhc3RlMCgiQ2x1c3RlciAiLCBuLCAiOyBjb3IgPCAwLjMiKSkKICAgICAgaWYobnJvdyhwbG90X2RmKSUlMj09MSl7CiAgICAgICAgcGx0ID0gcGx0ICsgdGhlbWUoYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQodmp1c3QgPSAwLjYsIGNvbG91ciA9IGMoImdyZXkxNyIsImdyZXk0NSIpKSkKICAgICAgfQogICAgICBwZGYocGFzdGUwKHBhdGhnbywgImhlcF9nb18iLCBjYywgIl9jbCIsIG4sICIucGRmIiksIGhlaWdodCA9IDMuMiwgd2lkdGggPSAzLjYsIHVzZURpbmdiYXRzID0gRikKICAgICAgcHJpbnQocGx0KQogICAgICBkZXYub2ZmKCkKICAgIH0KICB9Cn0KYGBgCgpQbG90cyBmb3IgaW5kaXZpZHVhbCBnZW5lcwoKYGBge3J9CmdlbmVwbG90X3RoZW1lID0gdGhlbWVfYncoKSsKICAgIHRoZW1lKGFzcGVjdC5yYXRpbyA9IDEvMS41LAogICAgICAgICAgcGFuZWwuZ3JpZCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgIGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dChjb2xvdXIgPSAiYmxhY2siLCBzaXplID0gNyksCiAgICAgICAgICBheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSA4KSwKICAgICAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEwLCBmYWNlID0gIml0YWxpYyIpLAogICAgICAgICAgcGxvdC50aXRsZS5wb3NpdGlvbiA9ICJwbG90IiwKICAgICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iLAogICAgICAgICAgbGVnZW5kLmJveC5tYXJnaW4gPSBtYXJnaW4oMCwwLDAsMCksCiAgICAgICAgICBsZWdlbmQuYm94LnNwYWNpbmcgPSB1bml0KDAuMDEsImNtIiksCiAgICAgICAgICBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gOCksCiAgICAgICAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDkpKQoKcGx0X2dlbmVfbGlzdCA9IGxpc3QoKQpmb3IoZyBpbiBnX2xpc3QpewogIHBsdF9kZiA9IGRhdGEuZnJhbWUoImV4cCIgPSBjKGhlcF9zaWdfZml0cyRoZWFsdGh5WyxnXSwgaGVwX3NpZ19maXRzJGVtYm9saXNlZFssZ10pLAogICAgICAgICAgICAgICAgICAgICJjb25kIiA9IHJlcChjKCJoZWFsdGh5IiwgImVtYm9saXNlZCIpLCBlYWNoID0gMTAwKSwKICAgICAgICAgICAgICAgICAgICAidCIgPSByZXAoMToxMDAsIDIpKQogIHBsdF9kZiRjb25kID0gZmFjdG9yKHBsdF9kZiRjb25kLCBsZXZlbHMgPSBjKCJoZWFsdGh5IiwgImVtYm9saXNlZCIpKQogIHBsdGVtYiA9IGdncGxvdChwbHRfZGYsIGFlcyh4ID0gdCwgeSA9IGV4cCwgZ3JvdXAgPSBjb25kLCBjb2wgPSBjb25kKSkrCiAgICBnZW9tX2xpbmUoc2l6ZSA9IDEuNSkrCiAgICBsYWJzKHggPSAiem9uYXRpb24iLCB5ID0gIkV4cHJlc3Npb24iLCB0aXRsZSA9IGcpKwogICAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBjb2xjb25kKSsKICAgIGdlbmVwbG90X3RoZW1lCiAgCiAgcGx0X2RmID0gZGF0YS5mcmFtZSgiZXhwIiA9IGMoaGVwX3NpZ19maXRzJGhlYWx0aHlbLGddLCBoZXBfc2lnX2ZpdHMkcmVnZW5lcmF0aW5nWyxnXSksCiAgICAgICAgICAgICAgICAgICAgImNvbmQiID0gcmVwKGMoImhlYWx0aHkiLCAicmVnZW5lcmF0aW5nIiksIGVhY2ggPSAxMDApLAogICAgICAgICAgICAgICAgICAgICJ0IiA9IHJlcCgxOjEwMCwgMikpCiAgcGx0X2RmJGNvbmQgPSBmYWN0b3IocGx0X2RmJGNvbmQsIGxldmVscyA9IGMoImhlYWx0aHkiLCAicmVnZW5lcmF0aW5nIikpCiAgcGx0cmVnID0gZ2dwbG90KHBsdF9kZiwgYWVzKHggPSB0LCB5ID0gZXhwLCBncm91cCA9IGNvbmQsIGNvbCA9IGNvbmQpKSsKICAgIGdlb21fbGluZShzaXplID0gMS41KSsKICAgIGxhYnMoeCA9ICJ6b25hdGlvbiIsIHkgPSAiRXhwcmVzc2lvbiIsIHRpdGxlID0gZykrCiAgICBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcyA9IGNvbGNvbmQpKwogICAgZ2VuZXBsb3RfdGhlbWUKICBwcmludChjb3dwbG90OjpwbG90X2dyaWQocGx0ZW1iLCBwbHRyZWcsIG5jb2wgPSAyKSkKICAKICBwbHRfZ2VuZV9saXN0W1tnXV0gPSBsaXN0KCJlbWJvbGlzZWQiID0gcGx0ZW1iLCAicmVnZW5lcmF0aW5nIiA9IHBsdHJlZykKfQpmb3IoZyBpbiBuYW1lcyhwbHRfZ2VuZV9saXN0KSl7CiAgZm9yKG4gaW4gbmFtZXMocGx0X2dlbmVfbGlzdFtbZ11dKSl7CiAgICBwZGYocGFzdGUwKCJmaWd1cmVfcGFuZWxzL2ZpZzMvaGVwX3pvbl8iLCBnLCAiXyIsICBuLCAiLnBkZiIpLCAKICAgICAgICBoZWlnaHQgPSAyLjIsIHdpZHRoID0gMi41LCB1c2VEaW5nYmF0cyA9IEYpCiAgICBwcmludChwbHRfZ2VuZV9saXN0W1tnXV1bW25dXSkKICAgIGRldi5vZmYoKQogIH0KfQpgYGAKClBsb3QgaW5kaXZpZHVhbCBnZW5lcyB3aXRoIGFsbCB0aHJlZSBjb25kaXRpb25zCgpgYGB7cn0KcGx0XzNfbGlzdCA9IGxpc3QoKQpmb3IoZyBpbiBnX2xpc3QpewogIHBsdF9kZiA9IGRhdGEuZnJhbWUoImV4cCIgPSBjKGhlcF9zaWdfZml0cyRoZWFsdGh5WyxnXSwgaGVwX3NpZ19maXRzJGVtYm9saXNlZFssZ10sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaGVwX3NpZ19maXRzJHJlZ2VuZXJhdGluZ1ssZ10pLAogICAgICAgICAgICAgICAgICAgICJjb25kIiA9IHJlcChjKCJoZWFsdGh5IiwgImVtYm9saXNlZCIsICJyZWdlbmVyYXRpbmciKSwgZWFjaCA9IDEwMCksCiAgICAgICAgICAgICAgICAgICAgInQiID0gcmVwKDE6MTAwLCAzKSkKICBwbHRfZGYkY29uZCA9IGZhY3RvcihwbHRfZGYkY29uZCwgbGV2ZWxzID0gYygiaGVhbHRoeSIsICJlbWJvbGlzZWQiLCAicmVnZW5lcmF0aW5nIikpCiAgcGx0XzNfbGlzdFtbZ11dID0gZ2dwbG90KHBsdF9kZiwgYWVzKHggPSB0LCB5ID0gZXhwLCBncm91cCA9IGNvbmQsIGNvbCA9IGNvbmQpKSsKICAgIGdlb21fbGluZShzaXplID0gMS41KSsKICAgIGxhYnMoeCA9ICJ6b25hdGlvbiIsIHkgPSAiRXhwcmVzc2lvbiIsIHRpdGxlID0gZywgY29sb3VyID0gIkNvbmRpdGlvbiIpKwogICAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBjb2xjb25kKSsKICAgIGd1aWRlcyhjb2xvdXIgPSBndWlkZV9sZWdlbmQodGl0bGUucG9zaXRpb24gPSAidG9wIikpKwogICAgZ2VuZXBsb3RfdGhlbWUKfQoKZm9yKGcgaW4gbmFtZXMocGx0XzNfbGlzdCkpewogIHBkZihwYXN0ZTAoImZpZ3VyZV9wYW5lbHMvZmlnMy9oZXBfem9uXyIsIGcsICJfYWxsLnBkZiIpLCAKICAgICAgaGVpZ2h0ID0gMi41LCB3aWR0aCA9IDMsIHVzZURpbmdiYXRzID0gRikKICBwcmludChwbHRfM19saXN0W1tnXV0pCiAgZGV2Lm9mZigpCn0KYGBgCgpQbG90IG1lYW4gcHJvZmlsZXMKCmBgYHtyfQpmb3IobiBpbiBuYW1lcyhoZXBfcmVzX2xpc3QpKXsKICBwbG90X2RmMiA9IGhlcF9yZXNfbGlzdFtbbl1dJGRmCiAgeHh4ID0gcGxvdF9kZjJbcGxvdF9kZjIkY29uZD09ImRpZmZlcmVuY2UiLF0KICBsYWJzZGYgPSBkYXRhLmZyYW1lKGxhYnMgPSBjKCJoaWdoZXIgaW5cbmhlYWx0aHkiLCBwYXN0ZTAoImhpZ2hlciBpblxuIiwgbikpLCBjb29yZCA9IGMoMC41LCAtMC41KSkKICBwbHQxID0gZ2dwbG90KHh4eCwgYWVzKHggPSBWYXIxLCB5ID0gdmFsdWUpKSsKICAgICAgZmFjZXRfZ3JpZCh+Y2xzLCBzY2FsZXMgPSAiZnJlZSIpKwogICAgICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwLCBjb2xvdXIgPSAiZ3JleTYwIiwgc2l6ZSA9IDAuNzUsIGxpbmV0eXBlID0gImRhc2hlZCIpKwogICAgICBzdGF0X3N1bW1hcnkoZnVuLmRhdGE9bWVhbl9jbF9ib290LCBjb2xvdXI9ImdyZXk0MCIsIGFscGhhID0gMC4zNSwgZ2VvbT0ibGluZXJhbmdlIiwgZ3JvdXA9MSkrCiAgICAgIHN0YXRfc3VtbWFyeShmdW49bWVhbiwgY29sb3VyPSJibGFjayIsIGdlb209ImxpbmUiLCBncm91cD0xKSsKICAgICAgbGFicyh4ID0gInpvbmF0aW9uIiwgeSA9ICJkaWZmZXJlbmNlIGluXG5zY2FsZWQgZXhwcmVzc2lvbiIpKwogICAgICBzY2FsZV95X2NvbnRpbnVvdXMobGltaXRzID0gYygtMSwxKSkrCiAgICAgIHRoZW1lX2J3KCkrCiAgICAgIHRoZW1lKGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dChjb2xvdXIgPSAiYmxhY2siLCBzaXplID0gNyksCiAgICAgICAgICAgIGF4aXMudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDgpKQogIHBsdDIgPSBnZ3Bsb3QoKSsKICAgIGdlb21fdGV4dChkYXRhID0gbGFic2RmLCBtYXBwaW5nID0gYWVzKHkgPSBjb29yZCwgbGFiZWwgPSBsYWJzKSwgCiAgICAgICAgICAgICAgeCA9IDAuNSwgYW5nbGUgPSAyNzAsIHNpemUgPSAzKSsKICAgIHNjYWxlX3hfY29udGludW91cyhsaW1pdHMgPSBjKDAsMSkpKwogICAgc2NhbGVfeV9jb250aW51b3VzKGxpbWl0cyA9IGMoLTEsMSkpKwogICAgY293cGxvdDo6dGhlbWVfbm90aGluZygpCiAgcGx0ID0gY293cGxvdDo6cGxvdF9ncmlkKHBsdDEsIHBsdDIsIG5jb2wgPSAyLCBucm93ID0gMSwgcmVsX3dpZHRocyA9IGMoMSwgMC4wODUpLCBhbGlnbiA9ICJodiIpCiAgCiAgcGRmKHBhc3RlMCgiZmlndXJlX3BhbmVscy9maWczL2hlcF96b25fIiwgbiwgIl9tZWFuLnBkZiIpLCBoZWlnaHQgPSAxLjgsIHdpZHRoID0gNiwgdXNlRGluZ2JhdHMgPSBGKQogIHByaW50KHBsdCkKICBkZXYub2ZmKCkKfQpgYGAKClBsb3QgaGVhdG1hcHMKCmBgYHtyLCBmaWcud2lkdGg9My44LCBmaWcuaGVpZ2h0PTIuNX0KIyBnZXQgcHJvZmlsZXMgZm9yIHBsb3R0aW5nCnVzZWdlbmVzID0gdW5pcXVlKGMoYXMuY2hhcmFjdGVyKGhlcF9yZXNfbGlzdCRlbWJvbGlzZWQkZGYkVmFyMiksCiAgICAgICAgICAgICAgICAgICAgYXMuY2hhcmFjdGVyKGhlcF9yZXNfbGlzdCRyZWdlbmVyYXRpbmckZGYkVmFyMikpKQoKYmluc19saXN0ID0gbGlzdCgpCmZvcihuIGluIG5hbWVzKGhlcF9jZWxscykpewogIHBsb3RfZGYgPSBjYmluZChkYXRhLmZyYW1lKCJwdCIgPSByZXAoMToxMCwgZWFjaCA9IDEwKSksaGVwX3NpZ19maXRzW1tuXV1bLHVzZWdlbmVzXSkKICBwbG90X2RmJGJpbnMxMCA9IGN1dChwbG90X2RmJHB0LCAxMCkKICBiaW5zX2xpc3RbW25dXSA9IHNhcHBseSh1c2VnZW5lcywgZnVuY3Rpb24oeCkgc2NhbGUodGFwcGx5KHBsb3RfZGZbLHhdLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBsb3RfZGYkYmluczEwLCBtZWFuKSlbMTA6MV0pCn0KYmluc19tZWFuID0gUmVkdWNlKHJiaW5kLCBiaW5zX2xpc3QpCmNvbG5hbWVzKGJpbnNfbWVhbikgPSB1c2VnZW5lcwoKIyBjaG9vc2UgZ2VuZXMgZm9yIHBsb3R0aW5nCmVjbF9nZW5lcyA9IG1lcmdlKHVuaXF1ZShoZXBfcmVzX2xpc3QkZW1ib2xpc2VkJGRmWyxjKDEsNCldKSwgaGVwX2ZpdHNfcXZhbCRlbWJvbGlzZWQkZmRyLCAKICAgICAgICAgICAgICAgICAgYnkueCA9IDEsICBieS55ID0gMCkKdG9wX2UgPSBlY2xfZ2VuZXMgJT4lIGdyb3VwX2J5KGNscykgJT4lIHNsaWNlX21pbihvcmRlcl9ieSA9IHB2YWxfbGlzdCwgbiA9IDUpCmVtYl9oZWF0ID0gcGhlYXRtYXAoYmluc19tZWFuWzE6MjAsYXMuY2hhcmFjdGVyKHRvcF9lJFZhcjIpXSwgc2hvd19yb3duYW1lcyA9IEYsIAogICAgICAgICAgICAgICAgICAgIGZvbnRzaXplX2NvbCA9IDYuMiwgYm9yZGVyX2NvbG9yID0gTkEsIGdhcHNfcm93ID0gYygxMCwyMCksIGdhcHNfY29sID0gc2VxKDUsIDIwLCA1KSwgCiAgICAgICAgICAgICAgICAgICAgY2x1c3RlcmluZ19tZXRob2QgPSAid2FyZC5EMiIsIGNsdXN0ZXJfcm93cyA9IEYsIGNsdXN0ZXJfY29scyA9IEYsIGZvbnRzaXplID0gNikKcGRmKCJmaWd1cmVfcGFuZWxzL2ZpZzMvaGVhdG1hcF96b25hdGlvbl9lbWIucGRmIiwgaGVpZ2h0PTIuNSwgd2lkdGg9My44LCB1c2VEaW5nYmF0cyA9IEYpCnByaW50KGVtYl9oZWF0KQpkZXYub2ZmKCkKd3JpdGUuY3N2KGVjbF9nZW5lcywgZmlsZSA9ICJmaWd1cmVfcGFuZWxzL2ZpZzMvaGVwX2VtYm9saXNlZF9jbHVzdGVyc19mZHIuY3N2Iiwgcm93Lm5hbWVzID0gRiwgcXVvdGUgPSBGKQoKcmNsX2dlbmVzID0gbWVyZ2UodW5pcXVlKGhlcF9yZXNfbGlzdCRyZWdlbmVyYXRpbmckZGZbLGMoMSw0KV0pLCBoZXBfZml0c19xdmFsJHJlZ2VuZXJhdGluZyRmZHIsIAogICAgICAgICAgICAgICAgICBieS54ID0gMSwgIGJ5LnkgPSAwKQp0b3BfciA9IHJjbF9nZW5lcyAlPiUgZ3JvdXBfYnkoY2xzKSAlPiUgc2xpY2VfbWluKG9yZGVyX2J5ID0gcHZhbF9saXN0LCBuID0gNSkKcmVnX2hlYXQgPSBwaGVhdG1hcChiaW5zX21lYW5bYygxOjEwLCAyMTozMCksYXMuY2hhcmFjdGVyKHRvcF9yJFZhcjIpXSwgc2hvd19yb3duYW1lcyA9IEYsIAogICAgICAgICAgICAgICAgICAgIGZvbnRzaXplX2NvbCA9IDcuNSwgYm9yZGVyX2NvbG9yID0gTkEsIGdhcHNfcm93ID0gYygxMCwyMCksIGdhcHNfY29sID0gc2VxKDUsIDIwLCA1KSwgCiAgICAgICAgICAgICAgICAgICAgY2x1c3RlcmluZ19tZXRob2QgPSAid2FyZC5EMiIsIGNsdXN0ZXJfcm93cyA9IEYsIGNsdXN0ZXJfY29scyA9IEYsIGZvbnRzaXplID0gNi43KQpwZGYoImZpZ3VyZV9wYW5lbHMvZmlnMy9oZWF0bWFwX3pvbmF0aW9uX3JlZy5wZGYiLCBoZWlnaHQ9Mi41LCB3aWR0aD0zLjgsIHVzZURpbmdiYXRzID0gRikKcHJpbnQocmVnX2hlYXQpCmRldi5vZmYoKQp3cml0ZS5jc3YocmNsX2dlbmVzLCBmaWxlID0gImZpZ3VyZV9wYW5lbHMvZmlnMy9oZXBfcmVnZW5fY2x1c3RlcnNfZmRyLmNzdiIsIHJvdy5uYW1lcyA9IEYsIHF1b3RlID0gRikKYGBgCgoKCiMgRmlndXJlIDQKIyMgTWFpbiBGaWd1cmUKTG9hZCBkYXRhCgpgYGB7cn0Kb25seV9lbmRfY2VsbHMgPSByZWFkUkRTKGZpbGUgPSAicmVzdWx0cy9lbmRvdGhlbGlhbC9vbmx5X2VuZF9jZWxsc196b24uUkRTIikKYWxsX2Nvcl9lbmQgPSByZWFkLmNzdigicmVzdWx0cy9lbmRvdGhlbGlhbC9jb3JyZWxhdGlvbnNfem9uYXRpb25fZW5kb3RoZWxpYWwuY3N2IiwgCiAgICAgICAgICAgICAgICAgICAgICAgaGVhZGVyID0gVCwgcm93Lm5hbWVzID0gMSkKZW5kX2ZpdHNfcXZhbCA9IHJlYWRSRFMoZmlsZSA9ICJyZXN1bHRzL2VuZG90aGVsaWFsL2VuZF9maXRzX3F2YWwuUkRTIikKbWtzaW1wID0gcmVhZC5jc3YoInJlc3VsdHMvZW5kb3RoZWxpYWwvbWFya2Vyc19lbmRvX3N1YnBvcF9zaW1wLmNzdiIsIGhlYWRlciA9IFQsIHJvdy5uYW1lcyA9IDEpCm1rc2ltcCA9IG1rc2ltcFtvcmRlcihta3NpbXAkYXZnX2xvZ0ZDLCBkZWNyZWFzaW5nID0gVCksXQoKdG9wX2dlbmVzID0gcmVhZFJEUyhmaWxlID0gInJlc3VsdHMvY29uZF9lZmZlY3QvdG9wX2dlbmVzX21rLlJEUyIpCgpnb19lbmQgPSByZWFkUkRTKCJyZXN1bHRzL2VuZG90aGVsaWFsL0dPVGVybXNfY29ycmVsYXRpb25zLlJEUyIpCmBgYAoKVU1BUHMKCmBgYHtyLCBmaWcuaGVpZ2h0PTIuMiwgZmlnLndpZHRoPTMuNn0KZW5kb19jb2wgPSBjKCJQZXJpcG9ydGFsIExTRUMiID0gImFxdWFtYXJpbmUyIiwgICJNaWR6b25hbCBMU0VDIiA9ICJhcXVhbWFyaW5lMyIsCiAgICAgICAgICAgICAiUGVyaWNlbnRyYWwgTFNFQyIgPSAiYXF1YW1hcmluZTQiLCAiTFNFQyAoZmVuZXN0ci4pIiA9ICJkYXJrc2xhdGVncmF5MSIsCiAgICAgICAgICAgICAiTFNFQyAocmVtb2RlbGxpbmcpIiA9ICJjeWFuNCIsICJMU0VDIChpbnRlcmZlcm9uKSIgPSAiZGFya3NsYXRlYmx1ZSIsCiAgICAgICAgICAgICAiTFNFQyAoaGlnaCBNVCAxKSIgPSAiYmx1ZXZpb2xldCIsICJMU0VDIChoaWdoIE1UIDIpIiA9ICJkYXJrdmlvbGV0IiwKICAgICAgICAgICAgICJMU0VDIChzdHJlc3MpIiA9ICJsaWdodGJsdWUiLCAiRUMgbm9uLUxTRUMiID0gImZvcmVzdGdyZWVuIiwgCiAgICAgICAgICAgICAiTHltcGhhdGljIEVDIiA9ICJjaGFydHJldXNlMyIsICJDeWNsaW5nIGNlbGxzIiA9ICJncmV5MjAiKQoKcGxvdF9kZiA9IGNiaW5kKG9ubHlfZW5kX2NlbGxzQG1ldGEuZGF0YVssYygiZW5kb19zaW1wIiwgIkNvbmRpdGlvbiIsICJEb25vciIpXSwKICAgICAgICAgICAgICAgIG9ubHlfZW5kX2NlbGxzQHJlZHVjdGlvbnMkdW1hcEBjZWxsLmVtYmVkZGluZ3MpCnBsb3RfZGYkQ29uZGl0aW9uID0gZmFjdG9yKHBsb3RfZGYkQ29uZGl0aW9uLCBsZXZlbHMgPSBjKCJoZWFsdGh5IiwgImVtYm9saXNlZCIsICJyZWdlbmVyYXRpbmciKSkKcGxvdF9kZiRlbmRvX3NpbXAgPSBmYWN0b3IocGxvdF9kZiRlbmRvX3NpbXAsIGxldmVscyA9IG5hbWVzKGVuZG9fY29sKSkKcGxvdF9kZiREb25vciA9IHBseXI6OnJldmFsdWUocGxvdF9kZiREb25vciwgYygiSEQxIiA9ICJzY19IMSIsICJIRDIiID0gInNjX0gyIiwgIkhEMyIgPSAic2NfSDMiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiREQxIiA9ICJzY19FMS9zY19SMSIsICJERDIiID0gInNjX0UyL3NjX1IyIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkREMyIgPSAic2NfRTMvc2NfUjMiLCAiREQ1IiA9ICJzY19FNC9zY19SNCIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJERDYiID0gInNjX0U1L3NjX1I1IiwgIkRENyIgPSAic2NfRTYvc2NfUjYiKSkKcGxvdF9kZiREb25vciA9IGZhY3RvcihwbG90X2RmJERvbm9yLCBsZXZlbHMgPSBjKCJzY19IMSIsICJzY19IMiIsICJzY19IMyIsICJzY19FMS9zY19SMSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAic2NfRTIvc2NfUjIiLCAic2NfRTMvc2NfUjMiLCAic2NfRTQvc2NfUjQiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJzY19FNS9zY19SNSIsICJzY19FNi9zY19SNiIpKQpzZXQuc2VlZCgxKQpwbG90X2RmID0gcGxvdF9kZltzYW1wbGUoMTpucm93KHBsb3RfZGYpLCBzaXplID0gbnJvdyhwbG90X2RmKSwgcmVwbGFjZSA9IEYpLF0KCnBsdF9zdWJ0eXBlcyA9IGdncGxvdChwbG90X2RmLCBhZXMoeCA9IFVNQVBfMSwgeSA9IFVNQVBfMiwgY29sb3VyID0gZW5kb19zaW1wKSkrCiAgZ2VvbV9wb2ludChzaXplID0gMC4xKSsKICBndWlkZXMoY29sb3VyID0gZ3VpZGVfbGVnZW5kKG92ZXJyaWRlLmFlcyA9IGxpc3Qoc2l6ZSA9IDEuNzUpKSkrCiAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBlbmRvX2NvbCkrCiAgdGhlbWUoYXNwZWN0LnJhdGlvID0gMSwKICAgICAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDgpLAogICAgICAgIGxlZ2VuZC5ib3guc3BhY2luZyA9IHVuaXQoMC4wMSwgImNtIiksCiAgICAgICAgYXhpcy5saW5lID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGV4dCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRpdGxlID0gZWxlbWVudF9ibGFuaygpKQoKcGx0X2NvbmQgPSBnZ3Bsb3QocGxvdF9kZiwgYWVzKHggPSBVTUFQXzEsIHkgPSBVTUFQXzIsIGNvbG91ciA9IENvbmRpdGlvbikpKwogIGdlb21fcG9pbnQoc2l6ZSA9IDAuMSkrCiAgZ3VpZGVzKGNvbG91ciA9IGd1aWRlX2xlZ2VuZChvdmVycmlkZS5hZXMgPSBsaXN0KHNpemUgPSAxLjc1KSkpKwogIHNjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzID0gY29sY29uZCkrCiAgdGhlbWUoYXNwZWN0LnJhdGlvID0gMSwKICAgICAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDgpLAogICAgICAgIGxlZ2VuZC5ib3guc3BhY2luZyA9IHVuaXQoMC4wMSwgImNtIiksCiAgICAgICAgYXhpcy5saW5lID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGV4dCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRpdGxlID0gZWxlbWVudF9ibGFuaygpKQoKcGx0X2RvbiA9IGdncGxvdChwbG90X2RmLCBhZXMoeCA9IFVNQVBfMSwgeSA9IFVNQVBfMiwgY29sb3VyID0gRG9ub3IpKSsKICBnZW9tX3BvaW50KHNpemUgPSAwLjEpKwogIGd1aWRlcyhjb2xvdXIgPSBndWlkZV9sZWdlbmQob3ZlcnJpZGUuYWVzID0gbGlzdChzaXplID0gMS43NSkpKSsKICBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcyA9IGNvbGRvbmFsbCkrCiAgdGhlbWUoYXNwZWN0LnJhdGlvID0gMSwKICAgICAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDgpLAogICAgICAgIGxlZ2VuZC5ib3guc3BhY2luZyA9IHVuaXQoMC4wMSwgImNtIiksCiAgICAgICAgYXhpcy5saW5lID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGV4dCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRpdGxlID0gZWxlbWVudF9ibGFuaygpKQoKcGRmKCJmaWd1cmVfcGFuZWxzL2ZpZ19lbmRvL3VtYXBfY2x1c3RlcnMucGRmIiwgaGVpZ2h0PTIuMiwgd2lkdGg9My42LCB1c2VEaW5nYmF0cyA9IEYpCnByaW50KHBsdF9zdWJ0eXBlcykKZGV2Lm9mZigpCnBkZigiZmlndXJlX3BhbmVscy9maWdfZW5kby91bWFwX2NvbmQucGRmIiwgaGVpZ2h0PTIuMiwgd2lkdGg9My42LCB1c2VEaW5nYmF0cyA9IEYpCnByaW50KHBsdF9jb25kKQpkZXYub2ZmKCkKcGRmKCJmaWd1cmVfcGFuZWxzL2ZpZ19lbmRvL3VtYXBfZG9ub3JzLnBkZiIsIGhlaWdodD0yLjIsIHdpZHRoPTMuNiwgdXNlRGluZ2JhdHMgPSBGKQpwcmludChwbHRfZG9uKQpkZXYub2ZmKCkKCnBuZygiZmlndXJlX3BhbmVscy9maWdfZW5kby91bWFwX2NsdXN0ZXJzLnBuZyIsIGhlaWdodD02LjI1LCB3aWR0aD02LjI1LCB1bml0PSJjbSIsIAogICAgcmVzPTYwMCwgYW50aWFsaWFzID0gInN1YnBpeGVsIikKcHJpbnQocGx0X3N1YnR5cGVzK3RoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikpCmRldi5vZmYoKQpwbmcoImZpZ3VyZV9wYW5lbHMvZmlnX2VuZG8vdW1hcF9jb25kLnBuZyIsIGhlaWdodD02LjI1LCB3aWR0aD02LjI1LCB1bml0PSJjbSIsIAogICAgcmVzPTYwMCwgYW50aWFsaWFzID0gInN1YnBpeGVsIikKcHJpbnQocGx0X2NvbmQrdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKSkKZGV2Lm9mZigpCnBuZygiZmlndXJlX3BhbmVscy9maWdfZW5kby91bWFwX2Rvbm9ycy5wbmciLCBoZWlnaHQ9Ni4yNSwgd2lkdGg9Ni4yNSwgdW5pdD0iY20iLCAKICAgIHJlcz02MDAsIGFudGlhbGlhcyA9ICJzdWJwaXhlbCIpCnByaW50KHBsdF9kb24rdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKSkKZGV2Lm9mZigpCmBgYAoKRnJlcXVlbmN5IHRhYmxlcwoKYGBge3IsIGZpZy53aWR0aD0zLCBmaWcuaGVpZ2h0PTN9CmRmX2NudCA9IHRhYmxlKG9ubHlfZW5kX2NlbGxzJGVuZG9fc2ltcCwgb25seV9lbmRfY2VsbHMkQ29uZGl0aW9uKQpkZl9jbnRfcGVyQ29uZCA9IHJlc2hhcGUyOjptZWx0KGFwcGx5KGRmX2NudCwgMiwgZnVuY3Rpb24oeCkgcm91bmQoeC9zdW0oeCkqMTAwLCAxKSkpCmRmX2NudF9wZXJDbCA9IHJlc2hhcGUyOjptZWx0KGFwcGx5KGRmX2NudCwgMSwgZnVuY3Rpb24oeCkgcm91bmQoeC9zdW0oeCkqMTAwLCAxKSkpCgptYXRfY250X2FsbCA9IHJlc2hhcGUyOjpkY2FzdChkYXRhID0gZGZfY250X3BlckNsLCBmb3JtdWxhID0gVmFyMSB+IFZhcjIsIHZhbHVlLnZhciA9ICJ2YWx1ZSIpCnJvd25hbWVzKG1hdF9jbnRfYWxsKSA9IG1hdF9jbnRfYWxsJFZhcjEKbWF0X2NudF9hbGwgPSB0KG1hdF9jbnRfYWxsWywtMV0pCmN0b3JkID0gaGNsdXN0KGRpc3QobWF0X2NudF9hbGxbLGMoMiwxLDMpXSkpJG9yZGVyCgpoZWF0cCA9IHBoZWF0bWFwOjpwaGVhdG1hcChtYXRfY250X2FsbFtjdG9yZCxjKDIsMSwzKV0sIGNsdXN0ZXJfY29scyA9IEYsIGNsdXN0ZXJfcm93cyA9IEYsIAogICAgICAgICAgICAgICAgICAgICAgICAgICB0cmVlaGVpZ2h0X3JvdyA9IEYsIGRpc3BsYXlfbnVtYmVycyA9IFQsIGZvbnRzaXplX251bWJlciA9IDcsIAogICAgICAgICAgICAgICAgICAgICAgICAgICBudW1iZXJfY29sb3IgPSBjKCJibGFjayIsICJ3aGl0ZSIpW2FzLmludGVnZXIobWF0X2NudF9hbGxbY3RvcmQsYygyLDEsMyldPjUwKSsxXSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3IgPSBjb2xvclJhbXBQYWxldHRlKGJyZXdlci5wYWwobiA9IDksIG5hbWUgPSAiQmx1ZXMiKSkoMTAwKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgZm9udHNpemVfcm93ID0gNy41LCBmb250c2l6ZV9jb2wgPSA3LjUsIGFuZ2xlX2NvbCA9IDApCgpwZGYoImZpZ3VyZV9wYW5lbHMvZmlnX2VuZG8vY2x1c3Rlcl9wcm9wb3J0aW9uX2NvbmQucGRmIiwgaGVpZ2h0PTMuMiwgd2lkdGg9My4zLCB1c2VEaW5nYmF0cyA9IEYpCnByaW50KGhlYXRwKQpkZXYub2ZmKCkKYGBgCgpNYXJrZXJzCgpgYGB7cn0KbWtwbG90ID0gYygiTUdQIiwgIkFRUDEiLCAiQ0xFQzE0QSIsICJFRE5SQiIsICJDTEVDMUIiLCAiQ0xFQzRHIiwgIlBMVkFQIiwgIlJCUDciLCAiQU5HUFQyIiwgIkNUR0YiLAogICAgICAgICAgICJJU0cxNSIsICJJRklUMyIsICJNUk8iLCAiRUdSMSIsIlBUR0RTIiwgIklOTVQiLCAiUFJPWDEiLCAiQ0NMMjEiLCAiVE9QMkEiKQoKZXhwZGYgPSByZXNoYXBlMjo6bWVsdChjYmluZChkYXRhLmZyYW1lKHQob25seV9lbmRfY2VsbHNAYXNzYXlzJFNDVEBkYXRhW21rcGxvdCxdKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJlbmRvX3NpbXAiID0gb25seV9lbmRfY2VsbHMkZW5kb19zaW1wKSkpCmV4cGRmJGVuZG9fc2ltcCA9IGZhY3RvcihleHBkZiRlbmRvX3NpbXAsIGxldmVscyA9IG5hbWVzKGVuZG9fY29sKSkKCnZpb3BsdCA9IGdncGxvdChleHBkZiwgYWVzKHggPSBlbmRvX3NpbXAsIHkgPSB2YWx1ZSwgZmlsbCA9IGVuZG9fc2ltcCkpKwogIGZhY2V0X2dyaWQodmFyaWFibGV+Liwgc2NhbGVzID0gImZyZWVfeSIpKwogIGdlb21fdmlvbGluKHNjYWxlID0gIndpZHRoIiwgY29sb3VyID0gImdyZXk4MiIpKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGVuZG9fY29sKSsKICBzY2FsZV95X2NvbnRpbnVvdXMoYnJlYWtzID0gYygwLCAyLCA0KSkrCiAgbGFicyh5ID0gIkV4cHJlc3Npb24iKSsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIsCiAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSAtMzAsIGhqdXN0ID0gMCwgdmp1c3QgPSAwLjkpLAogICAgICAgIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplID0gNi41KSwKICAgICAgICBheGlzLnRpY2tzID0gZWxlbWVudF9saW5lKCksCiAgICAgICAgc3RyaXAudGV4dC55ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gMCwgc2l6ZSA9IDcsIG1hcmdpbiA9IG1hcmdpbigwLDAsMCwwKSksCiAgICAgICAgc3RyaXAuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChjb2xvdXIgPSAid2hpdGUiLCBmaWxsID0gIndoaXRlIikpCgpwZGYoImZpZ3VyZV9wYW5lbHMvZmlnX2VuZG8vdmlvbGluc19tay5wZGYiLCBoZWlnaHQ9NS44LCB3aWR0aD0zLjQsIHVzZURpbmdiYXRzID0gRikKcHJpbnQodmlvcGx0KQpkZXYub2ZmKCkKCmJveHBsdCA9IGdncGxvdChleHBkZiwgYWVzKHggPSBlbmRvX3NpbXAsIHkgPSB2YWx1ZSwgZmlsbCA9IGVuZG9fc2ltcCkpKwogIGZhY2V0X2dyaWQodmFyaWFibGV+Liwgc2NhbGVzID0gImZyZWVfeSIpKwogIGdlb21fYm94cGxvdChjb2xvdXIgPSAiZ3JleTUwIiwgb3V0bGllci5zaGFwZSA9IE5BLCBzaXplID0gMC4yNSkrCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gZW5kb19jb2wpKwogIHNjYWxlX3lfY29udGludW91cyhicmVha3MgPSBjKDAsIDIsIDQpKSsKICBsYWJzKHkgPSAiRXhwcmVzc2lvbiIpKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwKICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IC0zMCwgaGp1c3QgPSAwLCB2anVzdCA9IDAuOSksCiAgICAgICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemUgPSA2LjUpLAogICAgICAgIGF4aXMudGlja3MgPSBlbGVtZW50X2xpbmUoKSwKICAgICAgICBzdHJpcC50ZXh0LnkgPSBlbGVtZW50X3RleHQoYW5nbGUgPSAwLCBzaXplID0gNywgbWFyZ2luID0gbWFyZ2luKDAsMCwwLDApKSwKICAgICAgICBzdHJpcC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGNvbG91ciA9ICJ3aGl0ZSIsIGZpbGwgPSAid2hpdGUiKSkKCnBkZigiZmlndXJlX3BhbmVscy9maWdfZW5kby9ib3hlc19tay5wZGYiLCBoZWlnaHQ9NS44LCB3aWR0aD0zLjQsIHVzZURpbmdiYXRzID0gRikKcHJpbnQoYm94cGx0KQpkZXYub2ZmKCkKYGBgCgpCaW5uZWQgem9uYXRpb24KCmBgYHtyfQpwbG90X2RmID0gb25seV9lbmRfY2VsbHNAbWV0YS5kYXRhW29ubHlfZW5kX2NlbGxzQG1ldGEuZGF0YSRlbmRvX3NpbXAgJWluJSBjKCJQZXJpcG9ydGFsIExTRUMiLCAiTWlkem9uYWwgTFNFQyIsICJQZXJpY2VudHJhbCBMU0VDIikgJiBvbmx5X2VuZF9jZWxsc0BtZXRhLmRhdGEkZ29vZGNsLF0KcGxvdF9kZiRiaW5zMTAwID0gY3V0KHBsb3RfZGYkem9uYXRpb25fcHQsIDEwKQpwbG90X2RmJENvbmRpdGlvbiA9IGZhY3RvcihwbG90X2RmJENvbmRpdGlvbiwgbGV2ZWxzID0gYygiaGVhbHRoeSIsICJlbWJvbGlzZWQiLCAicmVnZW5lcmF0aW5nIikpCmVuZF9kZiA9IGRhdGEuZnJhbWUodGFibGUocGxvdF9kZiRDb25kaXRpb24sIHBsb3RfZGYkYmluczEwKSkKZW5kX2RmID0gZW5kX2RmW29yZGVyKGVuZF9kZiRWYXIxKSxdCmVuZF9kZiRGcmVxbm9ybSA9IHVubGlzdCh0YXBwbHkoZW5kX2RmJEZyZXEsIGVuZF9kZiRWYXIxLCBmdW5jdGlvbih4KSB4L3N1bSh4KSkpCmVuZF9kZiRGcmVxbm9ybV9oID0gZW5kX2RmJEZyZXFub3JtL21lYW4oZW5kX2RmJEZyZXFub3JtW2VuZF9kZiRWYXIxPT0iaGVhbHRoeSJdKQoKcGx0X2Rpc3RzID0gZ2dwbG90KGVuZF9kZiwgYWVzKHggPSBWYXIyLCBmaWxsID0gVmFyMSwgeSA9IEZyZXFub3JtX2gpKSsKICAgICBmYWNldF93cmFwKH5WYXIxKSsKICAgICBnZW9tX2NvbCgpKwogICAgIGxhYnMoeCA9ICJ6b25hdGlvbiAoYmlubmVkKSIsIHkgPSAiUHJvcG9ydGlvbiBvZiBjZWxscyAoY29tcGFyZWQgdG8gaGVhbHRoeSkiKSsKICAgICBzY2FsZV95X2NvbnRpbnVvdXMoZXhwYW5kID0gYygwLDApLCBsYWJlbHMgPSBjKCIwIiwgIjAuNSIsICIxIiwgIjEuNSIsICIyIikpKwogICAgIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGNvbGNvbmQpKwogICAgIGNvb3JkX2ZsaXAoKSsKICAgICBndWlkZXMoZmlsbCA9IGd1aWRlX2xlZ2VuZCh0aXRsZS5wb3NpdGlvbiA9ICJsZWZ0IikpKwogICAgIHRoZW1lKGF4aXMudGV4dC55ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KHNpemUgPSA2KSwKICAgICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpCgpwZGYoImZpZ3VyZV9wYW5lbHMvZmlnX2VuZG8vZW5kb196b25hdGlvbl9jb25kaXRpb25EaXN0X25vcm0ucGRmIiwgCiAgICBoZWlnaHQgPSAyLCB3aWR0aCA9IDMuOCwgdXNlRGluZ2JhdHMgPSBGKQpwcmludChwbHRfZGlzdHMpCmRldi5vZmYoKQpgYGAKCkRvbm9yIGRpc3RyaWJ1dGlvbnMKCmBgYHtyfQplbmRfZGYgPSBvbmx5X2VuZF9jZWxsc0BtZXRhLmRhdGFbb25seV9lbmRfY2VsbHMkZ29vZGNsLF0KCmVuZF9kZiA9IGRhdGEuZnJhbWUodmFscyA9IGVuZF9kZiR6b25hdGlvbl9wdCwgCiAgICAgICAgICAgICAgICAgICAgQ29uZGl0aW9uID0gZW5kX2RmJENvbmRpdGlvbiwKICAgICAgICAgICAgICAgICAgICBEb25vciA9IGVuZF9kZiREb25vciwKICAgICAgICAgICAgICAgICAgICBjdCA9IGVuZF9kZiRlbmRvX3NpbXApCmVuZF9kZiRiaW5zMTAgPSBjdXQoZW5kX2RmJHZhbHMsIDEwKQplbmRfZGYkQ29uZGl0aW9uID0gZmFjdG9yKGVuZF9kZiRDb25kaXRpb24sIGxldmVscyA9IGMoImhlYWx0aHkiLCAicmVnZW5lcmF0aW5nIiwgImVtYm9saXNlZCIpKQplbmRfZGYkRG9ub3IgPSBmYWN0b3IoZW5kX2RmJERvbm9yKQplbmRfZGYkRG9ub3IgPSBwbHlyOjpyZXZhbHVlKGVuZF9kZiREb25vciwgYygiSEQxIiA9ICJzY19IMSIsICJIRDIiID0gInNjX0gyIiwgIkhEMyIgPSAic2NfSDMiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkREMSIgPSAic2NfUjEvRTEiLCAiREQyIiA9ICJzY19SMi9FMiIsICJERDMiID0gInNjX1IzL0UzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkRENSIgPSAic2NfUjQvRTQiLCAiREQ2IiA9ICJzY19SNS9FNSIsICJERDciID0gInNjX1I2L0U2IikpCmVuZF9kZiREb25vciA9IGZhY3RvcihlbmRfZGYkRG9ub3IsIGxldmVscyA9IGxldmVscyhlbmRfZGYkRG9ub3IpW2MoNzo5LCAxOjYpXSkKCmVuZF9kb24gPSBnZ3Bsb3QoZW5kX2RmLCBhZXMoeCA9IHZhbHMsIGNvbG91ciA9IENvbmRpdGlvbikpKwogIGZhY2V0X3dyYXAofkRvbm9yLCBzY2FsZXMgPSAiZnJlZV95IikrCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCkrCiAgZ2VvbV9kZW5zaXR5KHNpemUgPSAxLjA1KSsKICBsYWJzKHggPSAiWm9uYXRpb24iLCB5ID0gIkNlbGwgZGVuc2l0eSIpKwogIHNjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzID0gY29sY29uZCkrCiAgc2NhbGVfeV9jb250aW51b3VzKGV4cGFuZCA9IGMoMCwwKSkrCiAgY29vcmRfZmxpcCgpKwogIGd1aWRlcyhjb2xvdXIgPSBndWlkZV9sZWdlbmQodGl0bGUucG9zaXRpb24gPSAibGVmdCIsIG5jb2wgPSAzKSkrCiAgdGhlbWUoYXhpcy50ZXh0LnkgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy50aWNrcy54ID0gZWxlbWVudF9saW5lKCksCiAgICAgICAgc3RyaXAudGV4dCA9IGVsZW1lbnRfdGV4dChtYXJnaW4gPSBtYXJnaW4oMC4wNCwwLDAuMDQsMCwgImNtIiksIHNpemUgPSA3LjUpLAogICAgICAgIHN0cmlwLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJ3aGl0ZSIsIGNvbG91ciA9ICJ3aGl0ZSIpLAogICAgICAgIGxlZ2VuZC50aXRsZS5hbGlnbiA9IDAsCiAgICAgICAgYXNwZWN0LnJhdGlvID0gMC44LAogICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iLAogICAgICAgIGxlZ2VuZC5ib3gubWFyZ2luID0gbWFyZ2luKDAsMCwwLDApLAogICAgICAgIGxlZ2VuZC5ib3guc3BhY2luZyA9IHVuaXQoMC4wNSwgImNtIikpCgpwZGYoImZpZ3VyZV9wYW5lbHMvZmlnX2VuZG8vZW5kX3pvbmF0aW9uX0Rvbm9yc0NvbmQucGRmIiwgaGVpZ2h0ID0gMy44LCB3aWR0aCA9IDMuNCwgdXNlRGluZ2JhdHMgPSBGKQpwcmludChlbmRfZG9uKQpkZXYub2ZmKCkKYGBgCgpQcmVkaWN0ZWQgem9uYXRpb24gZm9yIG90aGVyIHBvcHVsYXRpb25zCgpgYGB7ciwgZmlnLndpZHRoPTMuODUsIGZpZy5oZWlnaHQ9My41fQpwbG90X2RmID0gb25seV9lbmRfY2VsbHNAbWV0YS5kYXRhW29ubHlfZW5kX2NlbGxzQG1ldGEuZGF0YSRlbmRvX3NpbXAgJWluJSBuYW1lcyhlbmRvX2NvbClbMTo5XSxdCnBsb3RfZGYkYmluczEwMCA9IGN1dChwbG90X2RmJHpvbmF0aW9uX3B0LCAxMCkKcGxvdF9kZiRDb25kaXRpb24gPSBmYWN0b3IocGxvdF9kZiRDb25kaXRpb24sIGxldmVscyA9IGMoImhlYWx0aHkiLCAiZW1ib2xpc2VkIiwgInJlZ2VuZXJhdGluZyIpKQpwbG90X2RmJGVuZG9fc2ltcCA9IGZhY3RvcihwbG90X2RmJGVuZG9fc2ltcCwgbGV2ZWxzID0gbmFtZXMoZW5kb19jb2wpKQoKcGxvdF9wdGFsbCA9IGdncGxvdChwbG90X2RmLCBhZXMoeSA9IHpvbmF0aW9uX3B0LCB4ID0gZW5kb19zaW1wLCBmaWxsID0gQ29uZGl0aW9uKSkrCiAgZmFjZXRfd3JhcCh+ZW5kb19zaW1wLCBzY2FsZXMgPSAiZnJlZV94IiwgbmNvbCA9IDMpKwogIGdlb21fdmlvbGluKCkrCiAgbGFicyh5ID0gInpvbmF0aW9uIiwgeCA9ICJjbHVzdGVycyIpKwogIHNjYWxlX3lfY29udGludW91cyhleHBhbmQgPSBjKDAsMCksIGJyZWFrcyA9IGMoMCwgMC4yNSwgMC41LCAwLjc1LCAxKSwgbGltaXRzID0gYygwLDEpKSsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjb2xjb25kKSsKICBndWlkZXMoZmlsbCA9IGd1aWRlX2xlZ2VuZCh0aXRsZS5wb3NpdGlvbiA9ICJsZWZ0IikpKwogIHRoZW1lX2J3KCkrCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy50aWNrcy54ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KGNvbG91ciA9ICJibGFjayIsIHNpemUgPSA3KSwKICAgICAgICBheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSA4KSwKICAgICAgICBzdHJpcC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAid2hpdGUiLCBjb2xvdXIgPSAiYmxhY2siKSwKICAgICAgICBzdHJpcC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSA4KSwKICAgICAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgbGVnZW5kLmtleS5zaXplID0gdW5pdCgwLjMsICJjbSIpLAogICAgICAgIGxlZ2VuZC5ib3guc3BhY2luZyA9IHVuaXQoMC4wMSwgImNtIiksCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIpCgpwZGYoImZpZ3VyZV9wYW5lbHMvZmlnX2VuZG8vem9uYXRpb25fYWxsTFNFQy5wZGYiLCBoZWlnaHQ9My41LCB3aWR0aD0zLjg1LCB1c2VEaW5nYmF0cyA9IEYpCnByaW50KHBsb3RfcHRhbGwpCmRldi5vZmYoKQpgYGAKCkhlYXRtYXAKCmBgYHtyfQpvbmx5X2VuZF9jZWxsc19zcGxpdCA9IFNwbGl0T2JqZWN0KG9ubHlfZW5kX2NlbGxzWyxvbmx5X2VuZF9jZWxscyRnb29kY2xdLCBzcGxpdC5ieSA9ICJDb25kaXRpb24iKQoKIyBmaWx0ZXIgbWFya2VycyBmcm9tIG90aGVyIGNlbGwgdHlwZXMgKGNhbiBjb250YW1pbmF0ZSkKbWtfb3RoZXJzID0gdW5pcXVlKHVubGlzdCh0b3BfZ2VuZXMkY2VsbF90eXBlWyFncmVwbCgiTFNFQyAiLCBuYW1lcyh0b3BfZ2VuZXMkY2VsbF90eXBlKSldKSkKY29yX3N1YiA9IGFsbF9jb3JfZW5kWyEoYWxsX2Nvcl9lbmQkZ2VuZSAlaW4lIG1rX290aGVycyksXQoKdG9wZ2VuZXMgPSB1bmlxdWUoYyhjb3Jfc3ViJGdlbmVbb3JkZXIoY29yX3N1YiRIdkUsIGRlY3JlYXNpbmcgPSBUKV1bMTozMF0sCiAgICAgICAgICAgICAgICAgICAgY29yX3N1YiRnZW5lW29yZGVyKGNvcl9zdWIkSHZSLCBkZWNyZWFzaW5nID0gVCldWzE6MzBdKSkKYm90dG9tZ2VuZXMgPSB1bmlxdWUoYyhjb3Jfc3ViJGdlbmVbb3JkZXIoY29yX3N1YiRIdkUsIGRlY3JlYXNpbmcgPSBGKV1bMTozNV0sCiAgICAgICAgICAgICAgICAgICAgY29yX3N1YiRnZW5lW29yZGVyKGNvcl9zdWIkSHZSLCBkZWNyZWFzaW5nID0gRildWzE6MzVdKSkKCnVzZWdlbmVzID0gYyh0b3BnZW5lcywgYm90dG9tZ2VuZXMpCgpiaW5zX2xpc3QgPSBsaXN0KCkKZm9yKG4gaW4gbmFtZXMob25seV9lbmRfY2VsbHNfc3BsaXQpKXsKICBwbG90X2RmID0gY2JpbmQoZGF0YS5mcmFtZSgicHQiID0gcmVwKDE6MTAsIGVhY2ggPSAxMCkpLGVuZF9maXRzX3F2YWxbW25dXSRmaXRzWyx1c2VnZW5lc10pCiAgcGxvdF9kZiRiaW5zMTAgPSBjdXQocGxvdF9kZiRwdCwgMTApCiAgYmluc19saXN0W1tuXV0gPSBzYXBwbHkodXNlZ2VuZXMsIGZ1bmN0aW9uKHgpIHNjYWxlKHRhcHBseShwbG90X2RmWyx4XSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwbG90X2RmJGJpbnMxMCwgbWVhbikpWzEwOjFdKQp9CmJpbnNfbWVhbiA9IFJlZHVjZShyYmluZCwgYmluc19saXN0KQoKaGN0ID0gaGNsdXN0KGRpc3QodChiaW5zX2xpc3QkaGVhbHRoeVssdG9wZ2VuZXNdKSksIG1ldGhvZCA9ICJ3YXJkLkQyIikKaGNiID0gaGNsdXN0KGRpc3QodChiaW5zX21lYW5bLGJvdHRvbWdlbmVzXSkpLCBtZXRob2QgPSAid2FyZC5EMiIpCm9yZCA9IGModG9wZ2VuZXNbaGN0JG9yZGVyXSwgYm90dG9tZ2VuZXNbaGNiJG9yZGVyXSkKY3V0YiA9IGZhY3RvcihjdXRyZWUoaGNiLCAxMClbaGNiJG9yZGVyXSwgbGV2ZWxzID0gdW5pcXVlKGN1dHJlZShoY2IsIDgpW2hjYiRvcmRlcl0pKQoKZ2FwcyA9IGN1bXN1bSh0YWJsZShjdXRiKSlbLTEwXStsZW5ndGgodG9wZ2VuZXMpCgpoZWF0X3BsdCA9IHBoZWF0bWFwKGJpbnNfbWVhblssb3JkXSwgc2hvd19yb3duYW1lcyA9IEYsIGZvbnRzaXplX2NvbCA9IDYuMiwgYm9yZGVyX2NvbG9yID0gTkEsCiAgICAgICAgICAgICAgICAgICAgZ2Fwc19yb3cgPSBjKDEwLDIwKSwgZ2Fwc19jb2wgPSBjKGxlbmd0aCh0b3BnZW5lcyksIGdhcHMpLAogICAgICAgICAgICAgICAgICAgIGNsdXN0ZXJpbmdfbWV0aG9kID0gIndhcmQuRDIiLCBjbHVzdGVyX3Jvd3MgPSBGLCBjbHVzdGVyX2NvbHMgPSBGKQoKcGRmKCJmaWd1cmVfcGFuZWxzL2ZpZ19lbmRvL2hlYXRtYXBfY29yWm9uLnBkZiIsIGhlaWdodD0zLCB3aWR0aD03LjgsIHVzZURpbmdiYXRzID0gRikKcHJpbnQoaGVhdF9wbHQpCmRldi5vZmYoKQpgYGAKCkdPIFRlcm1zCgpgYGB7cn0KZ29fdGhlbWUgPSB0aGVtZV9idygpKwogIHRoZW1lKGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dChjb2xvdXIgPSAiYmxhY2siLCBzaXplID0gNy41KSwKICAgICAgICBheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSA4KSwKICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSA5KSwKICAgICAgICBwbG90LnRpdGxlLnBvc2l0aW9uID0gInBsb3QiLAogICAgICAgIHBsb3Quc3VidGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDcuNSksCiAgICAgICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQodmp1c3QgPSAwLjYsIGNvbG91ciA9IGMoImdyZXk0NSIsICJncmV5MTciKSksCiAgICAgICAgcGFuZWwuZ3JpZC5tYWpvci55ID0gZWxlbWVudF9ibGFuaygpKQoKZ29wbHRGdW5jID0gZnVuY3Rpb24ocGxvdF9kZiwgdGl0ID0gIiIsIHN1YnRpdCA9ICIiKXsKICBwbG90X2RmJERlc2NyaXB0aW9uID0gYnJlYWtTdHIocGxvdF9kZiREZXNjcmlwdGlvbiwgMzApCiAgcGxvdF9kZiREZXNjcmlwdGlvbiA9IGZhY3RvcihwbG90X2RmJERlc2NyaXB0aW9uLCBsZXZlbHMgPSByZXYocGxvdF9kZiREZXNjcmlwdGlvbikpCiAgcGxvdF9kZiRmaWxsID0gYXMuY2hhcmFjdGVyKHJlcCgxOjIsIGNlaWxpbmcobnJvdyhwbG90X2RmKS8yKSkpWzE6bnJvdyhwbG90X2RmKV0KICBwbHQgPSBnZ3Bsb3QocGxvdF9kZiwgYWVzKHggPSAtbG9nMTAocXZhbHVlKSwgeSA9IERlc2NyaXB0aW9uLCBmaWxsID0gZmlsbCkpKwogICAgZ2VvbV9jb2woc2hvdy5sZWdlbmQgPSBGKSsKICAgIHNjYWxlX3hfY29udGludW91cyhleHBhbmQgPSBjKDAsMCksIGxpbSA9IGMoMCwgbWF4KC1sb2cxMChwbG90X2RmJHF2YWx1ZSkpKzEpKSsKICAgIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoImdyZXkxNyIsICJncmV5NDUiKSkrCiAgICBsYWJzKHRpdGxlID0gdGl0LCBzdWJ0aXRsZSA9IHN1YnRpdCkrCiAgICBnb190aGVtZQogIHJldHVybihwbHQpCn0KCnBkZigiZmlndXJlX3BhbmVscy9maWdfZW5kby9lbmRfZ29fZW1iX2NvcnIucGRmIiwgaGVpZ2h0ID0gMy4yLCB3aWR0aCA9IDMuNiwgdXNlRGluZ2JhdHMgPSBGKQpwcmludChnb3BsdEZ1bmMoZ29fZW5kJGNvcl9oZSwgdGl0ID0gIkdPIFRlcm1zIC0gRW1ib2xpc2VkIiwgc3VidGl0ID0gImNvciA+PSAwLjMiKSkKZGV2Lm9mZigpCgpwZGYoImZpZ3VyZV9wYW5lbHMvZmlnX2VuZG8vZW5kX2dvX3JlZ19jb3JyLnBkZiIsIGhlaWdodCA9IDMuMiwgd2lkdGggPSAzLjYsIHVzZURpbmdiYXRzID0gRikKcHJpbnQoZ29wbHRGdW5jKGdvX2VuZCRjb3JfaHIsIHRpdCA9ICJHTyBUZXJtcyAtIFJlZ2VuZXJhdGluZyIsIHN1YnRpdCA9ICJjb3IgPj0gMC4zIikpCmRldi5vZmYoKQpgYGAKCgoKIyBGaWd1cmUgNQojIyBNYWluIEZpZ3VyZQpUb3RhbCBpbnRlcmFjdGlvbnMgcGVyIGNlbGwgdHlwZSBpbiBlYWNoIGNvbmRpdGlvbgoKYGBge3J9Cm5ldF9uYW1lc19sID0gcmVhZFJEUyhmaWxlID0gInJlc3VsdHMvY2VsbF9jb21tL3VwZHQvY291bnRfbmV0X2xpc3QuUkRTIikKIyBsaXN0IHBlciBjb25kaXRpb24gd2l0aCBpbnRlcmFjdGlvbnMsIGdlbmVzLCBtZWFuCnJlZm9ybV9saXN0ID0gcmVhZFJEUyhmaWxlID0gInJlc3VsdHMvY2VsbF9jb21tL3VwZHQvcmVmb3JtX2xpc3QuUkRTIikKIyBsaXN0IHBlciBjb25kIHdpdGggbGlnYW5kIG9yIHJlY2VwdG9yIGV4cHJlc3Npb24gZm9yIGVhY2ggaW50ZXJhY3Rpb24Kc2NvcmluZ19tYXRzID0gcmVhZFJEUyhmaWxlID0gInJlc3VsdHMvY2VsbF9jb21tL3VwZHQvc2NvcmluZ19tYXRzLlJEUyIpCiMgcmVmb3JtX2xpc3QgKyBERSBpbmZvICsgdW5pcXVlbmVzcy9zcGVjaWZpY2l0eSBvZiBpbnRlcmFjdGlvbi9saWdhbmQvcmVjZXB0b3IKaW50ZXJfZGYgPSByZWFkUkRTKGZpbGUgPSAicmVzdWx0cy9jZWxsX2NvbW0vdXBkdC9jb25kX2RpZmZfaW50ZXJhY3RfREUuUkRTIikKIyBpbnRlcmFjdGlvbnMgcWl0aCBjZXJ0YWluIGZ1bmN0aW9ucyBpbnZvbHZpbmcgd2hpY2ggY2VsbCB0eXBlcyBhbmQgaW4gd2hpY2ggY29uZGl0aW9ucwpjdF9nX2NvbmRfYW5uID0gcmVhZFJEUyhmaWxlID0gInJlc3VsdHMvY2VsbF9jb21tL3VwZHQvY3RfZ19jb25kX2Fubi5SRFMiKQojIGludGVyYWN0aW9uIHdpdGggTCBhbmQgUiwgcGFpciBvZiBjZWxsIHR5cGVzLCBtZWFuIGV4cCwgYW5kIGZ1bmN0aW9uCmN0X2ludF9leHBfbCA9IHJlYWRSRFMoZmlsZSA9ICJyZXN1bHRzL2NlbGxfY29tbS91cGR0L2ludGVyYWN0X2NlbGx0eXBlX2V4cF9ncm91cF9saXN0LlJEUyIpCiMgYW5ub3RhdGlvbiBmb3IgYWxsIGludGVyYWN0aW9ucwppbnRlcl9hbm5vdCA9IHJlYWQuY3N2KCJkYXRhL2ludGVyYWN0aW9uX2Fubm90YXRpb24uY3N2IiwgaGVhZGVyID0gVCkKaW50ZXJfYW5ub3QkZnVuY3RbZ3JlcGwoImltbSIsIGludGVyX2Fubm90JGZ1bmN0KV0gPSAiaW1tdW5lIgppbnRlcl9hbm5vdCRmdW5jdFtncmVwbCgiaW5mbGFtIiwgaW50ZXJfYW5ub3QkZnVuY3QpXSA9ICJpbW11bmUiCiMgbXV0IGluZm8gZGF0YQpoZXJfYWxsaW50ID0gcmVhZFJEUyhmaWxlID0gIi4vcmVzdWx0cy9jZWxsX2NvbW0vdXBkdC9pbnRlcmFjdGlvbnNfbXV0SW5mb19jb25kQ29tcC5SRFMiKQojIEdTRUEgb24gbXV0dWFsIGluZm8gcmVzdWx0cwphbGxfZ3NlYV9saXN0ID0gcmVhZFJEUyhmaWxlID0gIi4vcmVzdWx0cy9jZWxsX2NvbW0vdXBkdC9hbGxnc2VhX2ludGVyYWN0aW9uc19tdXRJbmZvX2NvbmRDb21wLlJEUyIpCnNpbXBfZ3NlYV9saXN0ID0gcmVhZFJEUyhmaWxlID0gIi4vcmVzdWx0cy9jZWxsX2NvbW0vdXBkdC9zaW1wZ3NlYV9pbnRlcmFjdGlvbnNfbXV0SW5mb19jb25kQ29tcC5SRFMiKQojIG5ldHdvcmsgZGF0YQpsb2FkKCJyZXN1bHRzL2NlbGxfY29tbS91cGR0L21lZGlhbl9uZXR3b3Jrc19jb25kLlJEYXRhIikKbG9hZCgicmVzdWx0cy9jZWxsX2NvbW0vdXBkdC9uZXR3b3Jrc19jb25kLlJEYXRhIikKbG9hZCgicmVzdWx0cy9jZWxsX2NvbW0vdXBkdC9tZWRpYW5fbmV0d29ya3NfY29uZF9taWRjdC5SRGF0YSIpCmxvYWQoInJlc3VsdHMvY2VsbF9jb21tL3VwZHQvbWVkaWFuX25ldHdvcmtzX2NvbmRfdW1hcC5SRGF0YSIpCmxvYWQoInJlc3VsdHMvY2VsbF9jb21tL3VwZHQvbmV0d29ya3NfY29uZF91bWFwLlJEYXRhIikKbG9hZCgicmVzdWx0cy9jZWxsX2NvbW0vdXBkdC9tZWRpYW5fbmV0d29ya3NfY29uZF91bWFwX21pZGN0LlJEYXRhIikKY29tcGhfaW50ZXJzID0gcmVhZFJEUyhmaWxlID0gInJlc3VsdHMvY2VsbF9jb21tL3VwZHQvY29tcGhfaW50ZXJzLlJEUyIpCmBgYAoKUGxvdCBjaGFuZ2VzIGluIG51bWJlciBvZiBpbnRlcmFjdGlvbnMgcGVyIGNvbmRpdGlvbgoKYGBge3J9CiMgY29ycmVjdCBzb21lIG5hbWVzCnJlZm9ybV9saXN0X2ludCA9IGxpc3QoKQpmb3IobiBpbiBuYW1lcyhyZWZvcm1fbGlzdClbMTozXSl7CiAgcmVmb3JtX2xpc3RbW25dXSRjdDFbZ3JlcGwoIkhlcGEiLCByZWZvcm1fbGlzdFtbbl1dJGN0MSldID0gIkhlcGF0b2N5dGVzIgogIHJlZm9ybV9saXN0W1tuXV0kY3QyW2dyZXBsKCJIZXBhIiwgcmVmb3JtX2xpc3RbW25dXSRjdDIpXSA9ICJIZXBhdG9jeXRlcyIKICByZWZvcm1fbGlzdFtbbl1dJGN0MVtncmVwbCgiTFNFQ18iLCByZWZvcm1fbGlzdFtbbl1dJGN0MSldID0gIkxTRUMiCiAgcmVmb3JtX2xpc3RbW25dXSRjdDJbZ3JlcGwoIkxTRUNfIiwgcmVmb3JtX2xpc3RbW25dXSRjdDIpXSA9ICJMU0VDIgogIHJlZm9ybV9saXN0X2ludFtbbl1dID0gcmVmb3JtX2xpc3RbW25dXVtyZWZvcm1fbGlzdFtbbl1dJGN0MSE9IkRpdmlkaW5nIGNlbGxzIiAmCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVmb3JtX2xpc3RbW25dXSRjdDIhPSJEaXZpZGluZyBjZWxscyIsXQogIHJlZm9ybV9saXN0X2ludFtbbl1dID0gcmVmb3JtX2xpc3RfaW50W1tuXV1bIWR1cGxpY2F0ZWQocmVmb3JtX2xpc3RfaW50W1tuXV1bLDE6M10pLDE6M10KfQoKIyBjb3VudCBpbnRlcmFjdGlvbnMKaW5mZXJfZGYgPSBkYXRhLmZyYW1lKGV4cGFuZC5ncmlkKHVuaXF1ZShyZWZvcm1fbGlzdF9pbnQkaGVhbHRoeSRjdDEpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHVuaXF1ZShyZWZvcm1fbGlzdF9pbnQkaGVhbHRoeSRjdDEpKSkKbnIgPSBucm93KGluZmVyX2RmKQppbmZlcl9kZiA9IHJiaW5kKGluZmVyX2RmLCBpbmZlcl9kZiwgaW5mZXJfZGYpCmluZmVyX2RmJGNvdW50ID0gMAppbmZlcl9kZiRjb25kID0gcmVwKG5hbWVzKHJlZm9ybV9saXN0KVsxOjNdLCBlYWNoID0gbnIpCmNvbG5hbWVzKGluZmVyX2RmKVsxOjJdID0gYygiU09VUkNFIiwgIlRBUkdFVCIpCmZvcihpIGluIDE6bnJvdyhpbmZlcl9kZikpewogIHRtcCA9IHJlZm9ybV9saXN0X2ludFtbaW5mZXJfZGZbaSw0XV1dCiAgaW5mZXJfZGZbaSwzXSA9IGRpbSh0bXBbKHRtcCRjdDE9PWluZmVyX2RmW2ksMV0gJiB0bXAkY3QyPT1pbmZlcl9kZltpLDJdKSB8CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAodG1wJGN0Mj09aW5mZXJfZGZbaSwxXSAmIHRtcCRjdDE9PWluZmVyX2RmW2ksMl0pLF0pWzFdCn0KIyMgbWFrZSBvbmUgdG8gY291bnQgb3ZlciBhbGwKaW5mZXJfYWxsID0gZGF0YS5mcmFtZShleHBhbmQuZ3JpZCh1bmlxdWUocmVmb3JtX2xpc3RfaW50JGhlYWx0aHkkY3QxKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdW5pcXVlKHJlZm9ybV9saXN0X2ludCRoZWFsdGh5JGN0MSkpKQppbmZlcl9hbGwkY291bnQgPSAwCmNvbG5hbWVzKGluZmVyX2FsbClbMToyXSA9IGMoIlNPVVJDRSIsICJUQVJHRVQiKQpyZWZvcm1fYWxsX2ludCA9IHVuaXF1ZShSZWR1Y2UocmJpbmQsIHJlZm9ybV9saXN0X2ludCkpCmZvcihpIGluIDE6bnJvdyhpbmZlcl9hbGwpKXsKICBpbmZlcl9hbGxbaSwzXSA9IGluZmVyX2FsbFtpLDNdK2RpbSh0bXBbKHJlZm9ybV9hbGxfaW50JGN0MT09aW5mZXJfYWxsW2ksMV0gJiByZWZvcm1fYWxsX2ludCRjdDI9PWluZmVyX2FsbFtpLDJdKSB8CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKHJlZm9ybV9hbGxfaW50JGN0Mj09aW5mZXJfYWxsW2ksMV0gJiByZWZvcm1fYWxsX2ludCRjdDE9PWluZmVyX2FsbFtpLDJdKSxdKVsxXQp9CgppbmZlcl9kZl9saXN0ID0gbGlzdChoZWFsdGh5ID0gaW5mZXJfZGZbaW5mZXJfZGYkY29uZD09ImhlYWx0aHkiLF0sCiAgICAgICAgICAgICAgICAgICAgIGVtYm9saXNlZCA9IGluZmVyX2RmW2luZmVyX2RmJGNvbmQ9PSJlbWJvbGlzZWQiLF0sCiAgICAgICAgICAgICAgICAgICAgIHJlZ2VuZXJhdGluZyA9IGluZmVyX2RmW2luZmVyX2RmJGNvbmQ9PSJyZWdlbmVyYXRpbmciLF0sCiAgICAgICAgICAgICAgICAgICAgIGFsbCA9IGluZmVyX2FsbCkKCm5ldF9uYW1lc19hbGwgPSB0KFJlZHVjZShyYmluZCwgbGFwcGx5KGluZmVyX2RmX2xpc3RbMTozXSwgZnVuY3Rpb24oeCkgdGFwcGx5KHgkY291bnQsIHgkU09VUkNFLCBzdW0pKSkpCmNvbG5hbWVzKG5ldF9uYW1lc19hbGwpID0gbmFtZXMobmV0X25hbWVzX2wpWzE6M10KbmV0X25hbWVzX2FsbCA9IHJlc2hhcGUyOjptZWx0KG5ldF9uYW1lc19hbGwpCm5ldF9uYW1lc19hbGwkVmFyMSA9IGZhY3RvcihuZXRfbmFtZXNfYWxsJFZhcjEsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgbGV2ZWxzID0gbmV0X25hbWVzX2FsbFtuZXRfbmFtZXNfYWxsJFZhcjI9PSJoZWFsdGh5IiwiVmFyMSJdW29yZGVyKG5ldF9uYW1lc19hbGxbbmV0X25hbWVzX2FsbCRWYXIyPT0iaGVhbHRoeSIsInZhbHVlIl0sIGRlY3JlYXNpbmcgPSBGKV0pCgp0b3RhbF91bmlxdWUgPSBkYXRhLmZyYW1lKHQodChSZWR1Y2UocmJpbmQsIGxhcHBseShpbmZlcl9kZl9saXN0WzRdLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZnVuY3Rpb24oeCkgdGFwcGx5KHgkY291bnQsIHgkU09VUkNFLCBzdW0pKSkpKSkKdG90YWxfdW5pcXVlJFZhcjEgPSByb3duYW1lcyh0b3RhbF91bmlxdWUpCmNvbG5hbWVzKHRvdGFsX3VuaXF1ZSlbMV0gPSAidmFsdWUiCnRvdGFsX3VuaXF1ZSRWYXIyID0gInRvdGFsIHVuaXF1ZSIKCm5ldF9uYW1lc19hbGwkVmFyMSA9IGZhY3RvcihuZXRfbmFtZXNfYWxsJFZhcjEsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgbGV2ZWxzID0gdG90YWxfdW5pcXVlJFZhcjFbb3JkZXIodG90YWxfdW5pcXVlJHZhbHVlLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRlY3JlYXNpbmcgPSBGKV0pCnBsdF9jb3VudHMgPSBnZ3Bsb3QobmV0X25hbWVzX2FsbCwgYWVzKHggPSBWYXIxLCB5ID0gdmFsdWUpKSsKICBnZW9tX3BvaW50KG1hcHBpbmcgPSBhZXMoY29sb3VyID0gVmFyMiksIHNpemUgPSAxLjYpKwogIGdlb21fcG9pbnQoZGF0YSA9IHRvdGFsX3VuaXF1ZSwgbWFwcGluZyA9IGFlcyhzaGFwZSA9IFZhcjIpLCBzaXplID0gMS42KSsKICBjb29yZF9mbGlwKCkrCiAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBjb2xjb25kKSsKICBzY2FsZV9zaGFwZV9tYW51YWwodmFsdWVzID0gYyg0KSkrCiAgc2NhbGVfeV9jb250aW51b3VzKGV4cGFuZCA9IGMoMCwwKSwgbGltaXRzID0gYygwLDY1MDApKSsKICBsYWJzKHkgPSAiVG90YWwgaW50ZXJhY3Rpb25zIiwgeCA9ICJDZWxsIFR5cGUiLCBjb2xvdXIgPSAiQ29uZGl0aW9uIikrCiAgZ3VpZGVzKGNvbG91ciA9IGd1aWRlX2xlZ2VuZChvcmRlciA9IDEpLCBzaGFwZSA9IGd1aWRlX2xlZ2VuZChvcmRlciA9IDIsIHRpdGxlID0gTlVMTCkpKwogIHRoZW1lX2J3KCkrCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSAzMCwgdmp1c3QgPSAxLCBoanVzdCA9IDEpLAogICAgICAgIGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dChjb2xvdXIgPSAiYmxhY2siKSwKICAgICAgICBheGlzLnRpdGxlLnggPSBlbGVtZW50X3RleHQoc2l6ZSA9IDgpLAogICAgICAgIGxlZ2VuZC5tYXJnaW4gPSBtYXJnaW4oMSwgMSwgMSwgMSksCiAgICAgICAgbGVnZW5kLnNwYWNpbmcueCA9IHVuaXQoMC4wNSwgImNtIiksCiAgICAgICAgbGVnZW5kLmRpcmVjdGlvbiA9ICJob3Jpem9udGFsIixsZWdlbmQuYm94ID0gImhvcml6b250YWwiKQpsZWcgPSBjb3dwbG90OjpnZXRfbGVnZW5kKHBsdF9jb3VudHMpCgpwZXJjX2RmID0gZGF0YS5mcmFtZSgiVmFyMSIgPSBuZXRfbmFtZXNfYWxsJFZhcjEsCiAgICAgICAgICAgICAgICAgICAgICJWYXIyIiA9IG5ldF9uYW1lc19hbGwkVmFyMiwKICAgICAgICAgICAgICAgICAgICAgInBlcmMiID0gYyhyZXAoMCwgbGVuZ3RoKHVuaXF1ZShuZXRfbmFtZXNfYWxsJFZhcjEpKSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKG5ldF9uYW1lc19hbGwkdmFsdWVbbmV0X25hbWVzX2FsbCRWYXIyPT0iZW1ib2xpc2VkIl0tbmV0X25hbWVzX2FsbCR2YWx1ZVtuZXRfbmFtZXNfYWxsJFZhcjI9PSJoZWFsdGh5Il0pL25ldF9uYW1lc19hbGwkdmFsdWVbbmV0X25hbWVzX2FsbCRWYXIyPT0iaGVhbHRoeSJdLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIChuZXRfbmFtZXNfYWxsJHZhbHVlW25ldF9uYW1lc19hbGwkVmFyMj09InJlZ2VuZXJhdGluZyJdLW5ldF9uYW1lc19hbGwkdmFsdWVbbmV0X25hbWVzX2FsbCRWYXIyPT0iaGVhbHRoeSJdKS9uZXRfbmFtZXNfYWxsJHZhbHVlW25ldF9uYW1lc19hbGwkVmFyMj09ImhlYWx0aHkiXSkqMTAwKQpwZXJjX2RmJGNvbCA9IGlmZWxzZShwZXJjX2RmJHBlcmM+MCwgImdyZWVuIiwgInJlZCIpCnBlcmNfZGYgPSBwZXJjX2RmW3BlcmNfZGYkVmFyMiE9ImhlYWx0aHkiLF0KCnBlcmNfcGx0X2VtYiA9IGdncGxvdChwZXJjX2RmW3BlcmNfZGYkVmFyMj09ImVtYm9saXNlZCIsXSwgYWVzKHggPSBWYXIxLCB5ID0gcGVyYywgZmlsbCA9IGNvbCkpKwogIGdlb21fY29sKCkrCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygiZGVlcHNreWJsdWUxIiwgInJlZDEiKSkrCiAgc2NhbGVfeV9jb250aW51b3VzKGV4cGFuZCA9IGMoMCwwKSwgbGltaXRzID0gYygtNDUsNzApKSsKICBjb29yZF9mbGlwKCkrCiAgbGFicyh5ID0gIiUgY2hhbmdlXG5lbWJvbGlzZWQgdnMgaGVhbHRoeSIsIHggPSAiQ2VsbCBUeXBlIikrCiAgdGhlbWVfYncoKSsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDMwLCB2anVzdCA9IDEsIGhqdXN0ID0gMSwgY29sb3VyID0gImJsYWNrIiksCiAgICAgICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF90ZXh0KHNpemUgPSA4KSwKICAgICAgICBheGlzLnRpdGxlLnkgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy50aWNrcy55ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikKcGVyY19wbHRfcmVnID0gZ2dwbG90KHBlcmNfZGZbcGVyY19kZiRWYXIyPT0icmVnZW5lcmF0aW5nIixdLCBhZXMoeCA9IFZhcjEsIHkgPSBwZXJjLCBmaWxsID0gY29sKSkrCiAgZ2VvbV9jb2woKSsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCJkZWVwc2t5Ymx1ZTEiLCAicmVkMSIpKSsKICBzY2FsZV95X2NvbnRpbnVvdXMoZXhwYW5kID0gYygwLDApLCBsaW1pdHMgPSBjKC00NSw3MCkpKwogIGNvb3JkX2ZsaXAoKSsKICBsYWJzKHkgPSAiJSBjaGFuZ2VcbnJlZ2VuZXJhdGluZyB2cyBoZWFsdGh5IiwgeCA9ICJDZWxsIFR5cGUiKSsKICB0aGVtZV9idygpKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gMzAsIHZqdXN0ID0gMSwgaGp1c3QgPSAxLCBjb2xvdXIgPSAiYmxhY2siKSwKICAgICAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRpdGxlLnggPSBlbGVtZW50X3RleHQoc2l6ZSA9IDgpLAogICAgICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRpY2tzLnkgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQoKY293cGxvdDo6cGxvdF9ncmlkKGNvd3Bsb3Q6OnBsb3RfZ3JpZChwbHRfY291bnRzK3RoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBlcmNfcGx0X2VtYiwgcGVyY19wbHRfcmVnLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuY29sID0gMywgYWxpZ24gPSAiaCIsIGF4aXMgPSAiciIsIHJlbF93aWR0aHMgPSBjKDEsMC41LDAuNSkpLAogICAgICAgICAgICAgICAgICAgbGVnLCBucm93ID0gMiwgcmVsX2hlaWdodHMgPSBjKDEsIDAuMSkpCgpwZGYoImZpZ3VyZV9wYW5lbHNfcmV2MS9maWdfY29tbS9tYWluRmlnX2NvdW50c0NvbmQucGRmIiwgaGVpZ2h0ID0gNywgd2lkdGggPSA3KQpjb3dwbG90OjpwbG90X2dyaWQoY293cGxvdDo6cGxvdF9ncmlkKHBsdF9jb3VudHMrdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGVyY19wbHRfcmVnLCBwZXJjX3BsdF9lbWIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5jb2wgPSAzLCBhbGlnbiA9ICJoIiwgYXhpcyA9ICJyIiwgcmVsX3dpZHRocyA9IGMoMSwwLjQsMC40KSksCiAgICAgICAgICAgICAgICAgICBsZWcsIG5yb3cgPSAyLCByZWxfaGVpZ2h0cyA9IGMoMSwgMC4xKSkKZGV2Lm9mZigpCmBgYAoKTm9uLXViaXF1aXRvdXMgaW50ZXJhY3Rpb24gZnVuY3Rpb25zIHBlciBjZWxsIHR5cGUgYW5kIGNvbmRpdGlvbgoKYGBge3J9CiMgaW50ZXJhY3Rpb25zIGhhdmUgdG8gYmUgYWJzZW50IGluIGF0IGxlYXN0IG9uZSBjb25kaXRpb24KcGxvdF9kZiA9IGN0X2dfY29uZF9hbm5bY3RfZ19jb25kX2FubiRjZWxsdHlwZXMgJWluJSBjKCJTdGVsbGF0ZSBjZWxscyIsICJMU0VDIiwgIkt1cGZmZXIgY2VsbHMiLCAiY0RDcyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicERDcyIsICJFbmRvdGhlbGlhbCBjZWxscyAobm9uLUxTRUMpIikgJiAKICAgICAgICAgICAgICAgICAgICAgICAgICBjdF9nX2NvbmRfYW5uJGRlc2NyaXB0aW9uICVpbiUgYygiRUNNIiwgImluZmxhbW1hdGlvbiIsICJtaWdyYXRpb24iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJkZXZlbG9wbWVudCIsICJpbW11bmUgYWN0aXZpdHkiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiaW1tdW5lIHN1cHByZXNzaW9uIiwgImltbXVuZSByZWd1bGF0aW9uIiksXQpwbG90X2RmJGRlc2NyaXB0aW9uID0gZ3N1YigiICIsICJcbiIsIHBsb3RfZGYkZGVzY3JpcHRpb24sIGZpeGVkID0gVCkKcGxvdF9kZiRjZWxsdHlwZXMgPSBnc3ViKCIgKCIsICJcbigiLCBwbG90X2RmJGNlbGx0eXBlcywgZml4ZWQgPSBUKQpwbG90X2RmJGRlc2NyaXB0aW9uW2dyZXBsKCJpbW11bmUiLCBwbG90X2RmJGRlc2NyaXB0aW9uKSB8IAogICAgICAgICAgICAgICAgICAgICAgZ3JlcGwoImluZmxhbW0iLCBwbG90X2RmJGRlc2NyaXB0aW9uKV0gPSAiaW1tdW5lIgpiYXJfZnVuY19zdWIgPSBnZ3Bsb3QocGxvdF9kZiwgYWVzKHggPSBjb25kaXRpb24sIGZpbGwgPSBjb25kaXRpb24pKSsKICBmYWNldF9ncmlkKGNlbGx0eXBlc35kZXNjcmlwdGlvbiwgc2NhbGVzID0gImZyZWVfeSIpKwogIGdlb21fYmFyKCkrCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gY29sY29uZCkrCiAgdGhlbWVfY2xhc3NpYygpKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSwgdmp1c3QgPSAxLCBzaXplID0gNywgY29sb3VyID0gImJsYWNrIiksCiAgICAgICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDYuMywgY29sb3VyID0gImJsYWNrIiksCiAgICAgICAgYXhpcy50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gNyksCiAgICAgICAgYXhpcy5saW5lID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoY29sb3VyID0gImJsYWNrIiksCiAgICAgICAgcGFuZWwuZ3JpZC5tYWpvci55ID0gZWxlbWVudF9saW5lKCksCiAgICAgICAgc3RyaXAudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gNyksCiAgICAgICAgc3RyaXAuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBhc3BlY3QucmF0aW8gPSAxLAogICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikKCnBkZigiZmlndXJlX3BhbmVsc19yZXYxL2ZpZ19jb21tL21haW5GaWdfZnVuY1BhcnQucGRmIiwgaGVpZ2h0ID0gNS41LCB3aWR0aCA9IDQuNSkKcHJpbnQoYmFyX2Z1bmNfc3ViKQpkZXYub2ZmKCkKCnBsb3RfZGYgPSBjdF9nX2NvbmRfYW5uCnBsb3RfZGYkZGVzY3JpcHRpb24gPSBnc3ViKCIgIiwgIlxuIiwgcGxvdF9kZiRkZXNjcmlwdGlvbiwgZml4ZWQgPSBUKQpwbG90X2RmJGNlbGx0eXBlcyA9IGdzdWIoIiAoIiwgIlxuKCIsIHBsb3RfZGYkY2VsbHR5cGVzLCBmaXhlZCA9IFQpCnBsb3RfZGYkZGVzY3JpcHRpb25bZ3JlcGwoImltbXVuZSIsIHBsb3RfZGYkZGVzY3JpcHRpb24pIHwgCiAgICAgICAgICAgICAgICAgICAgICBncmVwbCgiaW5mbGFtbSIsIHBsb3RfZGYkZGVzY3JpcHRpb24pXSA9ICJpbW11bmUiCmJhcl9mdW5jX2FsbCA9IGdncGxvdChwbG90X2RmLCBhZXMoeCA9IGNvbmRpdGlvbiwgZmlsbCA9IGNvbmRpdGlvbikpKwogIGZhY2V0X2dyaWQoY2VsbHR5cGVzfmRlc2NyaXB0aW9uLCBzY2FsZXMgPSAiZnJlZV95IikrCiAgZ2VvbV9iYXIoKSsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjb2xjb25kKSsKICB0aGVtZV9jbGFzc2ljKCkrCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxLCB2anVzdCA9IDEsIHNpemUgPSA3LCBjb2xvdXIgPSAiYmxhY2siKSwKICAgICAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplID0gNi4zLCBjb2xvdXIgPSAiYmxhY2siKSwKICAgICAgICBheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSA3KSwKICAgICAgICBheGlzLmxpbmUgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChjb2xvdXIgPSAiYmxhY2siKSwKICAgICAgICBwYW5lbC5ncmlkLm1ham9yLnkgPSBlbGVtZW50X2xpbmUoKSwKICAgICAgICBzdHJpcC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSA3KSwKICAgICAgICBzdHJpcC5iYWNrZ3JvdW5kID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGFzcGVjdC5yYXRpbyA9IDEvMiwKICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpCgpwZGYoImZpZ3VyZV9wYW5lbHNfcmV2MS9maWdfY29tbS9zdXBwRmlnX2NvdW50c0Z1bmMucGRmIiwgcGFwZXIgPSAiYTQiLCB3aWR0aCA9IDksIGhlaWdodCA9IDEzLjUpCnByaW50KGJhcl9mdW5jX2FsbCkKZGV2Lm9mZigpCmBgYAoKSW50ZXJhY3Rpb24gZnVuY3Rpb25zIHBlciBjZWxsIHR5cGUgYW5kIGNvbmRpdGlvbiAodXNpbmcgYWxsIGludGVyYWN0aW9ucykKCmBgYHtyfQpwbG90X2RmID0gUmVkdWNlKHJiaW5kLCByZWZvcm1fbGlzdFsxOjNdKQpwbG90X2RmJGNvbmQgPSBjKHJlcCgiaGVhbHRoeSIsIG5yb3cocmVmb3JtX2xpc3QkaGVhbHRoeSkpLCAKICAgICAgICAgICAgICAgICByZXAoImVtYm9saXNlZCIsIG5yb3cocmVmb3JtX2xpc3QkZW1ib2xpc2VkKSksIAogICAgICAgICAgICAgICAgIHJlcCgicmVnZW5lcmF0aW5nIiwgbnJvdyhyZWZvcm1fbGlzdCRyZWdlbmVyYXRpbmcpKSkKcGxvdF9kZiA9IHVuaXF1ZShwbG90X2RmKQpwbG90X2RmID0gZGF0YS5mcmFtZShyYmluZChhcy5tYXRyaXgocGxvdF9kZlssYygxLDIsOCldKSwgYXMubWF0cml4KHBsb3RfZGZbLGMoMSwzLDgpXSkpKQpwbG90X2RmID0gbWVyZ2UocGxvdF9kZiwgaW50ZXJfYW5ub3QsIGJ5ID0gMSwgYWxsLnggPSBUKQpjb2xuYW1lcyhwbG90X2RmKSA9IGMoImludGVyYWN0aW9uIiwgImNlbGx0eXBlcyIsICJjb25kaXRpb24iLCAiZGVzY3JpcHRpb24iKQoKcGxvdF9kZiRkZXNjcmlwdGlvbiA9IGdzdWIoIiAiLCAiXG4iLCBwbG90X2RmJGRlc2NyaXB0aW9uLCBmaXhlZCA9IFQpCnBsb3RfZGYkY2VsbHR5cGVzID0gZ3N1YigiICgiLCAiXG4oIiwgcGxvdF9kZiRjZWxsdHlwZXMsIGZpeGVkID0gVCkKcGxvdF9kZiRkZXNjcmlwdGlvbltncmVwbCgiaW1tdW5lIiwgcGxvdF9kZiRkZXNjcmlwdGlvbikgfCAKICAgICAgICAgICAgICAgICAgICAgIGdyZXBsKCJpbmZsYW1tIiwgcGxvdF9kZiRkZXNjcmlwdGlvbildID0gImltbXVuZSIKYmFyX2Z1bmNfYWxsID0gZ2dwbG90KHBsb3RfZGYsIGFlcyh4ID0gY29uZGl0aW9uLCBmaWxsID0gY29uZGl0aW9uKSkrCiAgZmFjZXRfZ3JpZChkZXNjcmlwdGlvbn5jZWxsdHlwZXMsIHNjYWxlcyA9ICJmcmVlX3kiKSsKICBnZW9tX2JhcigpKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGNvbGNvbmQpKwogIHRoZW1lX2NsYXNzaWMoKSsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEsIHZqdXN0ID0gMSwgc2l6ZSA9IDcsIGNvbG91ciA9ICJibGFjayIpLAogICAgICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemUgPSA2LjMsIGNvbG91ciA9ICJibGFjayIpLAogICAgICAgIGF4aXMudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDcpLAogICAgICAgIGF4aXMubGluZSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGNvbG91ciA9ICJibGFjayIpLAogICAgICAgIHBhbmVsLmdyaWQubWFqb3IueSA9IGVsZW1lbnRfbGluZSgpLAogICAgICAgIHN0cmlwLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDcpLAogICAgICAgIHN0cmlwLmJhY2tncm91bmQgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXNwZWN0LnJhdGlvID0gMSwKICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpCmBgYAoKR1NFQSBxdmFsdWUgZm9yIGNoYW5naW5nIGludGVyYWN0aW9ucyAodXNpbmcgYWxsKQoKYGBge3J9CnBsb3RfZGYgPSBSZWR1Y2UocmJpbmQsIGFsbF9nc2VhX2xpc3QpCnBsb3RfZGYkcS52YWwgPSAtbG9nMTAocGxvdF9kZiRxLnZhbCswLjAwMDAwMDUpKihwbG90X2RmJHNzY29yZS9hYnMocGxvdF9kZiRzc2NvcmUpKQpwbG90X2RmJGNvbXAgPSBmYWN0b3IocGxvdF9kZiRjb21wLCBsZXZlbHMgPSByZXYoYygiaGUiLCJociIsImVyIikpKQptID0gdGFwcGx5KHBsb3RfZGYkcS52YWwsIHBsb3RfZGYkZ3JvdXAsbWVhbikKcGxvdF9kZiRncm91cCA9IGZhY3RvcihwbG90X2RmJGdyb3VwLCBsZXZlbHMgPSBuYW1lcyhtKVtvcmRlcihtLCBkZWNyZWFzaW5nID0gRildKQpwbG90X2RmID0gcGxvdF9kZltwbG90X2RmJGNvbXAhPSJlciIsXQpwbG90X2RmJGNvbXAgPSBhcy5jaGFyYWN0ZXIocGx5cjo6cmV2YWx1ZShwbG90X2RmJGNvbXAsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjKCJociIgPSAicmVnZW5lcmF0aW5nIiwgImhlIiA9ICJlbWJvbGlzZWQiLCAiZXIiID0gIm5vdGhpbmciKSkpCnBsb3RfZGYkY29tcCA9IGZhY3RvcihwbG90X2RmJGNvbXAsIGxldmVscyA9IGMoInJlZ2VuZXJhdGluZyIsICJlbWJvbGlzZWQiKSkKCmdzZWFwbHQgPSBnZ3Bsb3QocGxvdF9kZiwgYWVzKHggPSBxLnZhbCwgeSA9IGdyb3VwLCBmaWxsID0gY29tcCkpKwogIGdlb21fY29sKHBvc2l0aW9uID0gImRvZGdlIikrCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gYyhsb2cxMCgwLjA1KSwgLWxvZzEwKDAuMDUpKSwgbGluZXR5cGUgPSAiZGFzaGVkIikrCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gYygwKSkrCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gY29sY29uZCwgZHJvcCA9IFQpKwogIGd1aWRlcyhmaWxsID0gZ3VpZGVfbGVnZW5kKHRpdGxlID0gImhlYWx0aHkgdnMiLCByZXZlcnNlID0gVCkpKwogIGxhYnMoeCA9ICJxLXZhbHVlIHggc2NvcmUgc2lnbmFsIiwgeSA9ICJpbnRlcmFjdGlvbiB0eXBlIiwgZmlsbCA9ICJjb21wYXJpc29uIikrCiAgdGhlbWVfYncoKSsKICB0aGVtZShheGlzLnRleHQgPSBlbGVtZW50X3RleHQoY29sb3VyID0gImJsYWNrIiwgc2l6ZSA9IDcpLAogICAgICAgIGF4aXMudGl0bGUgPSBlbGVtZW50X3RleHQoY29sb3VyID0gImJsYWNrIiwgc2l6ZSA9IDcuNSksCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gYygwLDEpLAogICAgICAgIGxlZ2VuZC5qdXN0aWZpY2F0aW9uID0gYygtMC4wNSwxLjA1KSwKICAgICAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDcuNSksCiAgICAgICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDcpLAogICAgICAgIGxlZ2VuZC5tYXJnaW4gPSBtYXJnaW4oMCwwLDAsMCksCiAgICAgICAgbGVnZW5kLmtleS5zaXplID0gdW5pdCgwLjM1LCAiY20iKSkKCnBkZigiZmlndXJlX3BhbmVsc19yZXYxL2ZpZ19jb21tL21haW5GaWdfZnVuY0dTRUEucGRmIiwgaGVpZ2h0ID0gMi4yLCB3aWR0aCA9IDIuODUpCnByaW50KGdzZWFwbHQpCmRldi5vZmYoKQpgYGAKCkludGVyYWN0aW9uIGV4cHJlc3Npb24gbWF0cmljZXMKCmBgYHtyfQpncmFkZXhwY29sID0gYygiI2YzZWRmZiIsICIjZWNjOGZhIiwgIiM5ZTQyZDQiLCAiIzc5MmY5MSIpCgpmaWx0RnVuYyA9IGZ1bmN0aW9uKHgsIG11dHRociA9IDAsIGV4cHRociA9IDAuMTIsIG1pbmN0ID0gMyl7CiAgY29sZGYgPSB4Wyh4JG11dEluZm9faGU8PW11dHRociB8IHgkbXV0SW5mb19ocjw9bXV0dGhyKSwxOjhdCiAgY29sZGYgPSB4WywxOjhdCiAgY29sZGYkaW50bHIgPSBwYXN0ZTAoY29sZGYkbHIxLCAiIC1cbiAiLCBjb2xkZiRscjIpCiAgY29sZGYgPSB1bmlxdWUoY29sZGZbLGMoMiwzLDksNjo4KV0pCiAgbmludCA9IHRhYmxlKGNvbGRmJGludGxyKQogIGNvbGRmID0gY29sZGZbYXBwbHkoY29sZGZbLDQ6Nl0sIDEsIGZ1bmN0aW9uKHgpIGFueSh4Pj1leHB0aHIpKSAmIAogICAgICAgICAgICAgICAgICAoY29sZGYkaW50bHIgJWluJSBuYW1lcyhuaW50KVtuaW50PjFdIHwgYXBwbHkoY29sZGZbLDQ6Nl0sIDEsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZnVuY3Rpb24oeCkgYW55KHg+PWV4cHRocio4KSkpLF0KICBjb2xkZiA9IGRhdGEudGFibGU6OnJiaW5kbGlzdChsaXN0KHJlc2hhcGUyOjptZWx0KGNvbGRmWyxjKDMsMSw0OjYpXSksIAogICAgICAgICAgICAgICAgICAgICAgICAgcmVzaGFwZTI6Om1lbHQoY29sZGZbLGMoMywyLDQ6NildKSksIHVzZS5uYW1lcyA9IEYpCiAgY29sZGYkdmFyaWFibGUgPSB1bmxpc3QobGFwcGx5KHN0cnNwbGl0KGFzLmNoYXJhY3Rlcihjb2xkZiR2YXJpYWJsZSksICJfIiksIGZ1bmN0aW9uKHgpIHhbMV0pKQogIGNvbGRmJHZhcmlhYmxlID0gZmFjdG9yKGNvbGRmJHZhcmlhYmxlLCBsZXZlbHMgPSBjKCJoZWFsdGh5IiwgImVtYm9saXNlZCIsInJlZ2VuZXJhdGluZyIpKQogIGNvbGRmID0gY29sZGZbb3JkZXIoY29sZGYkdmFsdWUsIGRlY3JlYXNpbmcgPSBUKSxdCiAgY29sZGYgPSBjb2xkZlshZHVwbGljYXRlZChjb2xkZlssMTozXSksXQogIGNvbGRmJGN0MSA9IGdzdWIoIkVuZG90aGVsaWFsIGNlbGxzIiwgIkVDIiwgY29sZGYkY3QxKQogIGNvbGRmJGludGxyID0gZ3N1YigicmVjZXB0b3IiLCAiIiwgY29sZGYkaW50bHIpCiAgbmN0ID0gdGFibGUoY29sZGYkY3QxKQogIGNvbGRmID0gY29sZGZbY29sZGYkY3QxICVpbiUgbmFtZXMobmN0KVtuY3Q+PW1pbmN0KjNdLF0KICBuaW50ID0gdGFibGUoY29sZGYkaW50bHIpCiAgY29sZGYgPSBjb2xkZltjb2xkZiRpbnRsciAlaW4lIG5hbWVzKG5pbnQpW25pbnQ+M10sXQogIHJldHVybihjb2xkZikKfQpwbHRGdW5jID0gZnVuY3Rpb24oeCl7CiAgcGx0ID0gZ2dwbG90KHgsIGFlcyh4ID0gdmFyaWFibGUsIHkgPSBjdDEsIGZpbGwgPSB2YWx1ZSkpKwogICAgZmFjZXRfZ3JpZChpbnRscn4uLCBzY2FsZXMgPSAiZnJlZV95Iiwgc3BhY2UgPSAiZnJlZV95IikrCiAgICBnZW9tX3RpbGUoKSsKICAgIHNjYWxlX3hfZGlzY3JldGUoZXhwYW5kID0gYygwLDApKSsKICAgIHNjYWxlX2ZpbGxfZ3JhZGllbnRuKGNvbG9ycyA9IGdyYWRleHBjb2wpKwogICAgZ3VpZGVzKGZpbGwgPSBndWlkZV9jb2xvdXJiYXIoYmFyd2lkdGggPSB1bml0KDAuNCwgImNtIikpKSsKICAgIGxhYnMoeCA9ICJDb25kaXRpb24iLCB5ID0gIkNlbGwgdHlwZSIsIGZpbGwgPSAibWVhbiBleHAiKSsKICAgIHRoZW1lX2NsYXNzaWMoKSsKICAgIHRoZW1lKGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KGNvbG91ciA9ICJibGFjayIsIHNpemUgPSA3KSwKICAgICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGNvbG91ciA9ICJibGFjayIsIHNpemUgPSA2LjUsIGFuZ2xlID0gLTMwLCBoanVzdCA9IDAsIHZqdXN0ID0gMSksCiAgICAgICAgICBheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSA3KSwKICAgICAgICAgIGF4aXMubGluZSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJsZWZ0IiwKICAgICAgICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gNyksCiAgICAgICAgICBsZWdlbmQuYm94Lm1hcmdpbiA9IG1hcmdpbigwLDAsMCwwKSwKICAgICAgICAgIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSA2KSwKICAgICAgICAgIHN0cmlwLnRleHQueSA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDAsIHNpemUgPSA3LG1hcmdpbiA9IG1hcmdpbigwLDAsMCwzKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaGp1c3QgPSAwLjUsIGZhY2UgPSAiYm9sZCIpLAogICAgICAgICAgc3RyaXAuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSkKICByZXR1cm4ocGx0KQp9CnBsdEZ1bmMgPSBmdW5jdGlvbih4KXsKICBwbHQgPSBnZ3Bsb3QoeCwgYWVzKHkgPSB2YXJpYWJsZSwgeCA9IGN0MSwgZmlsbCA9IHZhbHVlKSkrCiAgICBmYWNldF9ncmlkKC5+aW50bHIsIHNjYWxlcyA9ICJmcmVlX3giLCBzcGFjZSA9ICJmcmVlX3giKSsKICAgIGdlb21fdGlsZSgpKwogICAgc2NhbGVfeV9kaXNjcmV0ZShleHBhbmQgPSBjKDAsMCksIGxpbWl0cyA9IHJldihsZXZlbHMoeCR2YXJpYWJsZSkpKSsKICAgIHNjYWxlX2ZpbGxfZ3JhZGllbnRuKGNvbG9ycyA9IGdyYWRleHBjb2wpKwogICAgZ3VpZGVzKGZpbGwgPSBndWlkZV9jb2xvdXJiYXIoYmFyaGVpZ2h0ID0gdW5pdCgwLjQsICJjbSIpKSkrCiAgICBsYWJzKHkgPSAiQ29uZGl0aW9uIiwgeCA9ICJDZWxsIHR5cGUiLCBmaWxsID0gIm1lYW4gZXhwIikrCiAgICB0aGVtZV9jbGFzc2ljKCkrCiAgICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChjb2xvdXIgPSAiYmxhY2siLCBzaXplID0gNywgYW5nbGUgPSA0NSwgaGp1c3QgPSAxLCB2anVzdCA9IDEpLAogICAgICAgICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoY29sb3VyID0gImJsYWNrIiwgc2l6ZSA9IDYuNSksCiAgICAgICAgICBheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSA3KSwKICAgICAgICAgIGF4aXMubGluZSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iLAogICAgICAgICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSA3KSwKICAgICAgICAgIGxlZ2VuZC5ib3gubWFyZ2luID0gbWFyZ2luKDAsMCwwLDApLAogICAgICAgICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDYpLAogICAgICAgICAgc3RyaXAudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIHNpemUgPSA3LCBtYXJnaW4gPSBtYXJnaW4oMCwwLDMsMCksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGhqdXN0ID0gMCwgdmp1c3QgPSAwLjUsIGZhY2UgPSAiYm9sZCIpLAogICAgICAgICAgc3RyaXAuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSkKICByZXR1cm4ocGx0KQp9CgpoZXJfYWxsaW50X2YgPSBtZXJnZShoZXJfYWxsaW50JGFsbCwgaW50ZXJfYW5ub3QsIGJ5ID0gMSwgYWxsLnggPSBUKQp3cml0ZS5jc3YoaGVyX2FsbGludF9mWyxjKDE6OCwyOCldLCBmaWxlID0gImZpZ3VyZV9wYW5lbHNfcmV2MS9maWdfY29tbS9hbGxfaW50ZXJhY3Rpb25zX2Z1bmN0aW9ucy5jc3YiLAogICAgICAgICAgY29sLm5hbWVzID0gVCwgcm93Lm5hbWVzID0gRiwgcXVvdGUgPSBGKQojIHJlbW92ZSBhdXRvY3JpbmUKaGVyX2FsbGludF9mID0gaGVyX2FsbGludF9mW2hlcl9hbGxpbnRfZiRjdDEhPWhlcl9hbGxpbnRfZiRjdDIsXQpoZXJfYWxsaW50X2YgPSBoZXJfYWxsaW50X2ZbIWlzLm5hKGhlcl9hbGxpbnRfZiRmdW5jdCksXQoKIyBFQ00KcGxvdF9kZiA9IGZpbHRGdW5jKGhlcl9hbGxpbnRfZltoZXJfYWxsaW50X2YkZnVuY3Q9PSJFQ00iLF0sIGV4cHRociA9IDAuMTUpCmVjbV9wbHQgPSBwbHRGdW5jKHBsb3RfZGYpCnBkZigiZmlndXJlX3BhbmVsc19yZXYxL2ZpZ19jb21tL21haW5GaWdfZWNtSW50ZXJhY3QucGRmIiwgaGVpZ2h0ID0gMywgd2lkdGggPSA3LjUpCnByaW50KGVjbV9wbHQpCmRldi5vZmYoKQoKIyBkZXYKcGxvdF9kZiA9IGZpbHRGdW5jKGhlcl9hbGxpbnRfZltoZXJfYWxsaW50X2YkZnVuY3Q9PSJkZXZlbG9wbWVudCIsXSwgZXhwdGhyID0gMC4xNSkKZGV2X3BsdCA9IHBsdEZ1bmMocGxvdF9kZikKcGRmKCJmaWd1cmVfcGFuZWxzX3JldjEvZmlnX2NvbW0vbWFpbkZpZ19kZXZJbnRlcmFjdC5wZGYiLCBoZWlnaHQgPSAzLCB3aWR0aCA9IDcuNSkKcHJpbnQoZGV2X3BsdCkKZGV2Lm9mZigpCmBgYAoKTmV0d29yayBwbG90cyAtIE1EUwoKYGBge3J9CnBsdGJvdGggPSBnZ3Bsb3QoKSsKICBnZW9tX3BvaW50KGRhdGEgPSBwb2ludF9jb25kX2RmLCBtYXBwaW5nID0gYWVzKHggPSBYMSwgeSA9IFgyLCBjb2xvdXIgPSBjdDIpLCAKICAgICAgICAgICAgIGFscGhhID0gMC42LCBzaG93LmxlZ2VuZCA9IE5BLCBzaXplID0gMS4zKSsKICBnZW9tX3NlZ21lbnQoZGF0YSA9IHBlX2xbWzJdXSwgCiAgICAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeCA9IFgxLngsIHhlbmQgPSBYMS55LCB5ID0gWDIueCwgeWVuZCA9IFgyLnksIHNpemUgPSBGcmVxKSwgCiAgICAgICAgICAgICAgIGFscGhhID0gMC4xNSwgc2hvdy5sZWdlbmQgPSBGKSsKICBnZW9tX3BvaW50KGRhdGEgPSBwZV9sW1sxXV0sIAogICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4ID0gWDEsIHkgPSBYMiwgZmlsbCA9IGN0KSwgCiAgICAgICAgICAgICBhbHBoYSA9IDEsIHBjaCA9IDIxLCBzaXplID0gNCkrCiAgZ3VpZGVzKGNvbG91ciA9IGd1aWRlX2xlZ2VuZChvdmVycmlkZS5hZXMgPSBsaXN0KHNpemUgPSAyLjMpKSkrCiAgc2NhbGVfc2l6ZV9jb250aW51b3VzKHJhbmdlID0gYygwLCA0KSwgbGltaXRzID0gcmFuZ2UocGVfbFtbMl1dJEZyZXEpKSsKICBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcyA9IGNvbHNtYWpvcikrCiAgI3NjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGNvbHNhbGxjdCkrCiAgdGhlbWVfY2xhc3NpYygpKyAKICB0aGVtZShhc3BlY3QucmF0aW8gPSAxLCAKICAgICAgICBheGlzLmxpbmUgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy50ZXh0ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGl0bGUgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy50aWNrcyA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgbGVnZW5kLmtleS5zaXplID0gdW5pdCgwLjM1LCAiY20iKSwKICAgICAgICBsZWdlbmQuc3BhY2luZy55ID0gdW5pdCgwLjEsICJjbSIpLAogICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikKcGRmKCJmaWd1cmVfcGFuZWxzX3JldjEvZmlnX2NvbW0vbWFpbkZpZ19pbmV0X2NvbmRfYWxsLnBkZiIsIAogICAgaGVpZ2h0ID0gMy4xLCB3aWR0aCA9IDUuMiwgdXNlRGluZ2JhdHMgPSBGKQpwcmludChwbHRib3RoKQpkZXYub2ZmKCkKCnBsdF9jb25kX2xfY2ggPSBsaXN0KCkKZm9yKGNjIGluIHVuaXF1ZShwZV9jb25kX2xfY2hbWzJdXSRjb25kaXRpb24pKXsKICBwbHRfY29uZF9sX2NoW1tjY11dID0gZ2dwbG90KCkrCiAgICBnZW9tX3NlZ21lbnQoZGF0YSA9IHBlX2NvbmRfbF9jaFtbMl1dW3BlX2NvbmRfbF9jaFtbMl1dJGNvbmRpdGlvbj09Y2MsXSwgCiAgICAgICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4ID0gWDEueCwgeGVuZCA9IFgxLnksIHkgPSBYMi54LCB5ZW5kID0gWDIueSwgc2l6ZSA9IEZyZXEsIGFscGhhID0gRnJlcSkpKwogICAgZ2VvbV9wb2ludChkYXRhID0gcGVfY29uZF9sX2NoW1sxXV0sIAogICAgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHggPSBYMSwgeSA9IFgyLCBmaWxsID0gY3QpLCAKICAgICAgICAgICAgICAgYWxwaGEgPSAxLCBwY2ggPSAyMSwgc2l6ZSA9IDQpKwogICAgc2NhbGVfc2l6ZV9jb250aW51b3VzKHJhbmdlID0gYygwLCA0KSwgbGltaXRzID0gcmFuZ2UocGVfY29uZF9sX2NoW1syXV0kRnJlcSkpKwogICAgc2NhbGVfYWxwaGFfY29udGludW91cyhyYW5nZSA9IGMoMCwgMSksIGxpbWl0cyA9IHJhbmdlKHBlX2NvbmRfbF9jaFtbMl1dJEZyZXEpKSsKICAgICNzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjb2xzYWxsY3QpKwogICAgbGFicyh0aXRsZSA9IGNjKSsKICAgIGd1aWRlcyhzaXplID0gZ3VpZGVfbGVnZW5kKGRpcmVjdGlvbiA9ICJob3Jpem9udGFsIiwgbnJvdyA9IDIpLAogICAgICAgICAgIGFscGhhID0gZ3VpZGVfbGVnZW5kKGRpcmVjdGlvbiA9ICJob3Jpem9udGFsIiwgbnJvdyA9IDIpKSsKICAgIHRoZW1lX2NsYXNzaWMoKSsgCiAgICB0aGVtZShhc3BlY3QucmF0aW8gPSAxLCAKICAgICAgICAgIGF4aXMubGluZSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgIGF4aXMudGV4dCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgIGF4aXMudGl0bGUgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgICBheGlzLnRpY2tzID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgICAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChjb2xvdXIgPSAiYmxhY2siKSwKICAgICAgICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgIGxlZ2VuZC5rZXkuc2l6ZSA9IHVuaXQoMC4zNSwgImNtIiksCiAgICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpCn0KcGx0X2NvbmRfbF9jaFtbImxlZyJdXSA9IGNvd3Bsb3Q6OmdldF9sZWdlbmQocGx0X2NvbmRfbF9jaFtbImhlYWx0aHkiXV0pCgpwZGYoImZpZ3VyZV9wYW5lbHNfcmV2MS9maWdfY29tbS9tYWluRmlnX2luZXRfY29uZF9tZWRpYW4ucGRmIiwgaGVpZ2h0ID0gMy4yLCB3aWR0aCA9IDUsIHVzZURpbmdiYXRzID0gRikKcHJpbnQocGx0X2NvbmRfbF9jaCRoZWFsdGh5KQpwcmludChwbHRfY29uZF9sX2NoJGVtYm9saXNlZCkKcHJpbnQocGx0X2NvbmRfbF9jaCRyZWdlbmVyYXRpbmcpCmRldi5vZmYoKQpgYGAKCk5ldHdvcmsgcGxvdHMgd2l0aCBtaWRkbGUgY2VsbCB0eXBlIHJlc29sdXRpb24gLSBNRFMKCmBgYHtyfQpwbHRib3RoID0gZ2dwbG90KCkrCiAgZ2VvbV9wb2ludChkYXRhID0gcG9pbnRfY29uZF9kZiwgbWFwcGluZyA9IGFlcyh4ID0gWDEsIHkgPSBYMiwgY29sb3VyID0gY3QyKSwgCiAgICAgICAgICAgICBhbHBoYSA9IDAuNiwgc2hvdy5sZWdlbmQgPSBOQSwgc2l6ZSA9IDEuMykrCiAgZ2VvbV9zZWdtZW50KGRhdGEgPSBwZV9taWRfbFtbMl1dLCAKICAgICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4ID0gWDEueCwgeGVuZCA9IFgxLnksIHkgPSBYMi54LCB5ZW5kID0gWDIueSwgc2l6ZSA9IEZyZXEpLCAKICAgICAgICAgICAgICAgYWxwaGEgPSAwLjE1LCBzaG93LmxlZ2VuZCA9IEYpKwogIGdlb21fcG9pbnQoZGF0YSA9IHBlX21pZF9sW1sxXV0sIAogICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4ID0gWDEsIHkgPSBYMiwgZmlsbCA9IGN0X21pZCksIAogICAgICAgICAgICAgYWxwaGEgPSAxLCBwY2ggPSAyMSwgc2l6ZSA9IDQpKwogIGd1aWRlcyhjb2xvdXIgPSBndWlkZV9sZWdlbmQob3ZlcnJpZGUuYWVzID0gbGlzdChzaXplID0gMi4zKSkpKwogIHNjYWxlX3NpemVfY29udGludW91cyhyYW5nZSA9IGMoMCwgNCksIGxpbWl0cyA9IHJhbmdlKHBlX21pZF9sW1syXV0kRnJlcSkpKwogIHNjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzID0gY29sc21ham9yKSsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjb2xzbWlkY3QpKwogIHRoZW1lX2NsYXNzaWMoKSsgCiAgdGhlbWUoYXNwZWN0LnJhdGlvID0gMSwgCiAgICAgICAgYXhpcy5saW5lID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGV4dCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRpdGxlID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGlja3MgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGxlZ2VuZC5rZXkuc2l6ZSA9IHVuaXQoMC4zNSwgImNtIiksCiAgICAgICAgbGVnZW5kLnNwYWNpbmcueSA9IHVuaXQoMC4xLCAiY20iKSwKICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpCnBkZigiZmlndXJlX3BhbmVsc19yZXYxL2ZpZ19jb21tL21haW5GaWdfaW5ldF9jb25kX21pZC5wZGYiLCAKICAgIGhlaWdodCA9IDMuMSwgd2lkdGggPSA1LjIsIHVzZURpbmdiYXRzID0gRikKcHJpbnQocGx0Ym90aCkKZGV2Lm9mZigpCgpwbHRfY29uZF9sX2NoID0gbGlzdCgpCmZvcihjYyBpbiB1bmlxdWUocGVfY29uZF9sX21pZFtbMl1dJGNvbmRpdGlvbikpewogIHBsdF9jb25kX2xfY2hbW2NjXV0gPSBnZ3Bsb3QoKSsKICAgIGdlb21fc2VnbWVudChkYXRhID0gcGVfY29uZF9sX21pZFtbMl1dW3BlX2NvbmRfbF9taWRbWzJdXSRjb25kaXRpb249PWNjLF0sIAogICAgICAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeCA9IFgxLngsIHhlbmQgPSBYMS55LCB5ID0gWDIueCwgeWVuZCA9IFgyLnksIHNpemUgPSBGcmVxLCBhbHBoYSA9IEZyZXEpKSsKICAgIGdlb21fcG9pbnQoZGF0YSA9IHBlX2NvbmRfbF9taWRbWzFdXSwgCiAgICAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeCA9IFgxLCB5ID0gWDIsIGZpbGwgPSBjdF9taWQpLCAKICAgICAgICAgICAgICAgYWxwaGEgPSAxLCBwY2ggPSAyMSwgc2l6ZSA9IDQpKwogICAgc2NhbGVfc2l6ZV9jb250aW51b3VzKHJhbmdlID0gYygwLCA0KSwgbGltaXRzID0gcmFuZ2UocGVfY29uZF9sX21pZFtbMl1dJEZyZXEpKSsKICAgIHNjYWxlX2FscGhhX2NvbnRpbnVvdXMocmFuZ2UgPSBjKDAsIDEpLCBsaW1pdHMgPSByYW5nZShwZV9jb25kX2xfbWlkW1syXV0kRnJlcSkpKwogICAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gY29sc21pZGN0KSsKICAgIGxhYnModGl0bGUgPSBjYykrCiAgICBndWlkZXMoc2l6ZSA9IGd1aWRlX2xlZ2VuZChkaXJlY3Rpb24gPSAiaG9yaXpvbnRhbCIsIG5yb3cgPSAyKSwKICAgICAgICAgICBhbHBoYSA9IGd1aWRlX2xlZ2VuZChkaXJlY3Rpb24gPSAiaG9yaXpvbnRhbCIsIG5yb3cgPSAyKSkrCiAgICB0aGVtZV9jbGFzc2ljKCkrIAogICAgdGhlbWUoYXNwZWN0LnJhdGlvID0gMSwgCiAgICAgICAgICBheGlzLmxpbmUgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgICBheGlzLnRleHQgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgICBheGlzLnRpdGxlID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgICAgYXhpcy50aWNrcyA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoY29sb3VyID0gImJsYWNrIiksCiAgICAgICAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgICBsZWdlbmQua2V5LnNpemUgPSB1bml0KDAuMzUsICJjbSIpKQp9CgpwZGYoImZpZ3VyZV9wYW5lbHNfcmV2MS9maWdfY29tbS9tYWluRmlnX2luZXRfY29uZF9tZWRpYW5fbWlkLnBkZiIsIAogICAgaGVpZ2h0ID0gMy4yLCB3aWR0aCA9IDUsIHVzZURpbmdiYXRzID0gRikKcHJpbnQocGx0X2NvbmRfbF9jaCRoZWFsdGh5KQpwcmludChwbHRfY29uZF9sX2NoJGVtYm9saXNlZCkKcHJpbnQocGx0X2NvbmRfbF9jaCRyZWdlbmVyYXRpbmcpCmRldi5vZmYoKQpgYGAKCk5ldHdvcmsgcGxvdHMgLSBVTUFQCgpgYGB7cn0KcGx0Ym90aCA9IGdncGxvdCgpKwogIGdlb21fcG9pbnQoZGF0YSA9IHBvaW50X2NvbmRfdW1hcF9kZiwgbWFwcGluZyA9IGFlcyh4ID0gWDEsIHkgPSBYMiwgY29sb3VyID0gY3QyKSwgCiAgICAgICAgICAgICBhbHBoYSA9IDAuNiwgc2hvdy5sZWdlbmQgPSBOQSwgc2l6ZSA9IDEuMykrCiAgZ2VvbV9zZWdtZW50KGRhdGEgPSBwZV91bWFwX2xbWzJdXSwgCiAgICAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeCA9IFgxLngsIHhlbmQgPSBYMS55LCB5ID0gWDIueCwgeWVuZCA9IFgyLnksIHNpemUgPSBGcmVxKSwgCiAgICAgICAgICAgICAgIGFscGhhID0gMC4xNSwgc2hvdy5sZWdlbmQgPSBGKSsKICBnZW9tX3BvaW50KGRhdGEgPSBwZV91bWFwX2xbWzFdXSwgCiAgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHggPSBYMSwgeSA9IFgyLCBmaWxsID0gY3QpLCAKICAgICAgICAgICAgIGFscGhhID0gMSwgcGNoID0gMjEsIHNpemUgPSA0KSsKICBndWlkZXMoY29sb3VyID0gZ3VpZGVfbGVnZW5kKG92ZXJyaWRlLmFlcyA9IGxpc3Qoc2l6ZSA9IDIuMykpKSsKICBzY2FsZV9zaXplX2NvbnRpbnVvdXMocmFuZ2UgPSBjKDAsIDQpLCBsaW1pdHMgPSByYW5nZShwZV9sW1syXV0kRnJlcSkpKwogIHNjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzID0gY29sc21ham9yKSsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjb2xzYWxsY3QpKwogIHRoZW1lX2NsYXNzaWMoKSsgCiAgdGhlbWUoYXNwZWN0LnJhdGlvID0gMSwgCiAgICAgICAgYXhpcy5saW5lID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGV4dCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRpdGxlID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGlja3MgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGxlZ2VuZC5rZXkuc2l6ZSA9IHVuaXQoMC4zNSwgImNtIiksCiAgICAgICAgbGVnZW5kLnNwYWNpbmcueSA9IHVuaXQoMC4xLCAiY20iKSwKICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpCnBkZigiZmlndXJlX3BhbmVsc19yZXYxL2ZpZ19jb21tL21haW5GaWdfaW5ldF9jb25kX3VtYXBfYWxsLnBkZiIsIGhlaWdodCA9IDMuMSwgd2lkdGggPSA1LjIsIHVzZURpbmdiYXRzID0gRikKcHJpbnQocGx0Ym90aCkKZGV2Lm9mZigpCgpwbHRfY29uZF9sX2NoID0gbGlzdCgpCmZvcihjYyBpbiB1bmlxdWUocGVfdW1hcF9jb25kX2xfY2hbWzJdXSRjb25kKSl7CiAgcGx0X2NvbmRfbF9jaFtbY2NdXSA9IGdncGxvdCgpKwogICAgZ2VvbV9zZWdtZW50KGRhdGEgPSBwZV91bWFwX2NvbmRfbF9jaFtbMl1dW3BlX3VtYXBfY29uZF9sX2NoW1syXV0kY29uZD09Y2MsXSwgCiAgICAgICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4ID0gWDEueCwgeGVuZCA9IFgxLnksIHkgPSBYMi54LCB5ZW5kID0gWDIueSwgc2l6ZSA9IEZyZXEsIGFscGhhID0gRnJlcSkpKwogICAgZ2VvbV9wb2ludChkYXRhID0gcGVfdW1hcF9jb25kX2xfY2hbWzFdXSwgCiAgICAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeCA9IFgxLCB5ID0gWDIsIGZpbGwgPSBjdCksIAogICAgICAgICAgICAgICBhbHBoYSA9IDEsIHBjaCA9IDIxLCBzaXplID0gNCkrCiAgICBzY2FsZV9zaXplX2NvbnRpbnVvdXMocmFuZ2UgPSBjKDAsIDQpLCBsaW1pdHMgPSByYW5nZShwZV91bWFwX2NvbmRfbF9jaFtbMl1dJEZyZXEpKSsKICAgIHNjYWxlX2FscGhhX2NvbnRpbnVvdXMocmFuZ2UgPSBjKDAsIDEpLCBsaW1pdHMgPSByYW5nZShwZV91bWFwX2NvbmRfbF9jaFtbMl1dJEZyZXEpKSsKICAgIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGNvbHNhbGxjdCkrCiAgICBsYWJzKHRpdGxlID0gY2MpKwogICAgZ3VpZGVzKHNpemUgPSBndWlkZV9sZWdlbmQoZGlyZWN0aW9uID0gImhvcml6b250YWwiLCBucm93ID0gMiksCiAgICAgICAgICAgYWxwaGEgPSBndWlkZV9sZWdlbmQoZGlyZWN0aW9uID0gImhvcml6b250YWwiLCBucm93ID0gMikpKwogICAgdGhlbWVfY2xhc3NpYygpKyAKICAgIHRoZW1lKGFzcGVjdC5yYXRpbyA9IDEsIAogICAgICAgICAgYXhpcy5saW5lID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgICAgYXhpcy50ZXh0ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgICAgYXhpcy50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgIGF4aXMudGlja3MgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgICBwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGNvbG91ciA9ICJibGFjayIpLAogICAgICAgICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgICAgbGVnZW5kLmtleS5zaXplID0gdW5pdCgwLjM1LCAiY20iKSwKICAgICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikKfQpwbHRfY29uZF9sX2NoW1sibGVnIl1dID0gY293cGxvdDo6Z2V0X2xlZ2VuZChwbHRfY29uZF9sX2NoW1siaGVhbHRoeSJdXSkKCnBkZigiZmlndXJlX3BhbmVsc19yZXYxL2ZpZ19jb21tL21haW5GaWdfaW5ldF9jb25kX3VtYXBfbWVkaWFuLnBkZiIsIGhlaWdodCA9IDMuMiwgd2lkdGggPSA1LCB1c2VEaW5nYmF0cyA9IEYpCnByaW50KHBsdF9jb25kX2xfY2gkaGVhbHRoeSkKcHJpbnQocGx0X2NvbmRfbF9jaCRlbWJvbGlzZWQpCnByaW50KHBsdF9jb25kX2xfY2gkcmVnZW5lcmF0aW5nKQpkZXYub2ZmKCkKYGBgCgpOZXR3b3JrIHBsb3RzIHdpdGggbWlkZGxlIGNlbGwgdHlwZSByZXNvbHV0aW9uIC0gVU1BUAoKYGBge3J9CnBsdGJvdGggPSBnZ3Bsb3QoKSsKICBnZW9tX3BvaW50KGRhdGEgPSBwb2ludF9jb25kX3VtYXBfZGYsIG1hcHBpbmcgPSBhZXMoeCA9IFgxLCB5ID0gWDIsIGNvbG91ciA9IGN0MiksIAogICAgICAgICAgICAgYWxwaGEgPSAwLjYsIHNob3cubGVnZW5kID0gTkEsIHNpemUgPSAxLjMpKwogIGdlb21fc2VnbWVudChkYXRhID0gcGVfdW1hcF9taWRfbFtbMl1dLCAKICAgICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4ID0gWDEueCwgeGVuZCA9IFgxLnksIHkgPSBYMi54LCB5ZW5kID0gWDIueSwgc2l6ZSA9IEZyZXEpLCAKICAgICAgICAgICAgICAgYWxwaGEgPSAwLjE1LCBzaG93LmxlZ2VuZCA9IEYpKwogIGdlb21fcG9pbnQoZGF0YSA9IHBlX3VtYXBfbWlkX2xbWzFdXSwgCiAgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHggPSBYMSwgeSA9IFgyLCBmaWxsID0gY3RfbWlkKSwgCiAgICAgICAgICAgICBhbHBoYSA9IDEsIHBjaCA9IDIxLCBzaXplID0gNCkrCiAgZ3VpZGVzKGNvbG91ciA9IGd1aWRlX2xlZ2VuZChvdmVycmlkZS5hZXMgPSBsaXN0KHNpemUgPSAyLjMpKSkrCiAgc2NhbGVfc2l6ZV9jb250aW51b3VzKHJhbmdlID0gYygwLCA0KSkrCiAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBjb2xzbWFqb3IpKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGNvbHNtaWRjdCkrCiAgdGhlbWVfY2xhc3NpYygpKyAKICB0aGVtZShhc3BlY3QucmF0aW8gPSAxLCAKICAgICAgICBheGlzLmxpbmUgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy50ZXh0ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGl0bGUgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy50aWNrcyA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgbGVnZW5kLmtleS5zaXplID0gdW5pdCgwLjM1LCAiY20iKSwKICAgICAgICBsZWdlbmQuc3BhY2luZy55ID0gdW5pdCgwLjEsICJjbSIpLAogICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikKcGRmKCJmaWd1cmVfcGFuZWxzX3JldjEvZmlnX2NvbW0vbWFpbkZpZ19pbmV0X2NvbmRfdW1hcF9hbGxfbWlkLnBkZiIsIGhlaWdodCA9IDMuMSwgd2lkdGggPSA1LjIsIHVzZURpbmdiYXRzID0gRikKcHJpbnQocGx0Ym90aCkKZGV2Lm9mZigpCgpwbHRfY29uZF9sX2NoID0gbGlzdCgpCmZvcihjYyBpbiB1bmlxdWUocGVfdW1hcF9jb25kX2xfbWlkW1syXV0kY29uZCkpewogIHBsdF9jb25kX2xfY2hbW2NjXV0gPSBnZ3Bsb3QoKSsKICAgIGdlb21fc2VnbWVudChkYXRhID0gcGVfdW1hcF9jb25kX2xfbWlkW1syXV1bcGVfdW1hcF9jb25kX2xfbWlkW1syXV0kY29uZD09Y2MsXSwgCiAgICAgICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4ID0gWDEueCwgeGVuZCA9IFgxLnksIHkgPSBYMi54LCB5ZW5kID0gWDIueSwgc2l6ZSA9IEZyZXEsIGFscGhhID0gRnJlcSkpKwogICAgZ2VvbV9wb2ludChkYXRhID0gcGVfdW1hcF9jb25kX2xfbWlkW1sxXV0sIAogICAgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHggPSBYMSwgeSA9IFgyLCBmaWxsID0gY3RfbWlkKSwgCiAgICAgICAgICAgICAgIGFscGhhID0gMSwgcGNoID0gMjEsIHNpemUgPSA0KSsKICAgIHNjYWxlX3NpemVfY29udGludW91cyhyYW5nZSA9IGMoMCwgNCksIGxpbWl0cyA9IHJhbmdlKHBlX3VtYXBfY29uZF9sX21pZFtbMl1dJEZyZXEpKSsKICAgIHNjYWxlX2FscGhhX2NvbnRpbnVvdXMocmFuZ2UgPSBjKDAsIDEpLCBsaW1pdHMgPSByYW5nZShwZV91bWFwX2NvbmRfbF9taWRbWzJdXSRGcmVxKSkrCiAgICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjb2xzbWlkY3QpKwogICAgbGFicyh0aXRsZSA9IGNjKSsKICAgIGd1aWRlcyhzaXplID0gZ3VpZGVfbGVnZW5kKGRpcmVjdGlvbiA9ICJob3Jpem9udGFsIiwgbnJvdyA9IDIpLAogICAgICAgICAgIGFscGhhID0gZ3VpZGVfbGVnZW5kKGRpcmVjdGlvbiA9ICJob3Jpem9udGFsIiwgbnJvdyA9IDIpKSsKICAgIHRoZW1lX2NsYXNzaWMoKSsgCiAgICB0aGVtZShhc3BlY3QucmF0aW8gPSAxLCAKICAgICAgICAgIGF4aXMubGluZSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgIGF4aXMudGV4dCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgIGF4aXMudGl0bGUgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgICBheGlzLnRpY2tzID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgICAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChjb2xvdXIgPSAiYmxhY2siKSwKICAgICAgICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgIGxlZ2VuZC5rZXkuc2l6ZSA9IHVuaXQoMC4zNSwgImNtIikpCn0KcGx0X2NvbmRfbF9jaFtbImxlZyJdXSA9IGNvd3Bsb3Q6OmdldF9sZWdlbmQocGx0X2NvbmRfbF9jaFtbImhlYWx0aHkiXV0pCgpwZGYoImZpZ3VyZV9wYW5lbHNfcmV2MS9maWdfY29tbS9tYWluRmlnX2luZXRfY29uZF91bWFwX21lZGlhbl9taWQucGRmIiwgaGVpZ2h0ID0gMy4yLCB3aWR0aCA9IDUsIHVzZURpbmdiYXRzID0gRikKcHJpbnQocGx0X2NvbmRfbF9jaCRoZWFsdGh5KQpwcmludChwbHRfY29uZF9sX2NoJGVtYm9saXNlZCkKcHJpbnQocGx0X2NvbmRfbF9jaCRyZWdlbmVyYXRpbmcpCmRldi5vZmYoKQpgYGAKCkhlYXRtYXBzIGZvciBpbnRlcmFjdGlvbnMgd2l0aCBpbW11bmUgY2VsbHMKCmBgYHtyfQojIGludGVyYWN0aW9ucyB1bmlxdWUgdG8gaGVhbHRoeSBvciB0byBlbWIvcmVnZW4KY29tcGhfaW50ZXJzID0gYyhzZXRkaWZmKGludGVyX2RmJGhlYWx0aHkkaWRfY3BfaW50ZXJhY3Rpb24sCiAgICAgICAgICAgICAgICAgICAgICAgICBjKGludGVyX2RmJGVtYm9saXNlZCRpZF9jcF9pbnRlcmFjdGlvbiwgaW50ZXJfZGYkcmVnZW5lcmF0aW5nJGlkX2NwX2ludGVyYWN0aW9uKSksCiAgICAgICAgICAgICAgICAgc2V0ZGlmZihpbnRlcl9kZiRlbWJvbGlzZWQkaWRfY3BfaW50ZXJhY3Rpb24sIGludGVyX2RmJGhlYWx0aHkkaWRfY3BfaW50ZXJhY3Rpb24pLAogICAgICAgICAgICAgICAgIHNldGRpZmYoaW50ZXJfZGYkcmVnZW5lcmF0aW5nJGlkX2NwX2ludGVyYWN0aW9uLCBpbnRlcl9kZiRoZWFsdGh5JGlkX2NwX2ludGVyYWN0aW9uKSkKCmVkZ2VfbWluID0gZWRnZV9jb25kX2RmWyxjKDE6NCw5OjEyKV0KZWRnZV9taW4gPSBtZXJnZShlZGdlX21pbiwgdW5pcXVlKGhlcl9hbGxpbnRfZlssYygxLDEzKV0pLCBieS54ID0gMywgYnkueSA9IDEsIGFsbC54ID0gVCkKZWRnZV9taW4gPSBtZXJnZShlZGdlX21pbiwgdW5pcXVlKGhlcl9hbGxpbnRfZlssYygxLDE3KV0pLCBieS54ID0gMSwgYnkueSA9IDEsIGFsbC54ID0gVCkKZWRnZV9taW4gPSBlZGdlX21pbltlZGdlX21pbiRtYWpfZzE9PSJJbW11bmUiIHwgZWRnZV9taW4kbWFqX2cyPT0iSW1tdW5lIixdCmVkZ2VfbWluID0gZWRnZV9taW5bZWRnZV9taW4kY3RfZzEhPWVkZ2VfbWluJGN0X2cyLF0KZWRnZV9taW4gPSBlZGdlX21pbltlZGdlX21pbiRpZF9jcF9pbnRlcmFjdGlvbiAlaW4lIGNvbXBoX2ludGVycyxdCgpkZXZkZiA9IGZpbHRGdW5jKGhlcl9hbGxpbnRfZltoZXJfYWxsaW50X2YkZnVuY3Q9PSJkZXZlbG9wbWVudCIsXSwgZXhwdGhyID0gMC4xNSkKZWNtZGYgPSBmaWx0RnVuYyhoZXJfYWxsaW50X2ZbaGVyX2FsbGludF9mJGZ1bmN0PT0iRUNNIixdLCBleHB0aHIgPSAwLjE1KQoKcGxvdF9kZiA9IGZpbHRGdW5jKGhlcl9hbGxpbnRfZltoZXJfYWxsaW50X2YkaWRfY3BfaW50ZXJhY3Rpb24gJWluJSB1bmlxdWUoZWRnZV9taW4kaWRfY3BfaW50ZXJhY3Rpb24pLF0sCiAgICAgICAgICAgICAgICAgICBleHB0aHIgPSAwLjA3LCBtaW5jdCA9IDIpCnBsb3RfZGYgPSBwbG90X2RmWyEocGxvdF9kZiRpbnRsciAlaW4lIGMoZGV2ZGYkaW50bHIsIGVjbWRmJGludGxyKSksXQppbW1fcGx0ID0gcGx0RnVuYyhwbG90X2RmKQpwZGYoImZpZ3VyZV9wYW5lbHNfcmV2MS9maWdfY29tbS9tYWluRmlnX2ltbXVuZU5ldEludGVyYWN0X21hbnkucGRmIiwgaGVpZ2h0ID0gMywgd2lkdGggPSAyMCkKcHJpbnQoaW1tX3BsdCkKZGV2Lm9mZigpCgpwbG90X2RmID0gZmlsdEZ1bmMoaGVyX2FsbGludF9mW2hlcl9hbGxpbnRfZiRpZF9jcF9pbnRlcmFjdGlvbiAlaW4lIHVuaXF1ZShlZGdlX21pbiRpZF9jcF9pbnRlcmFjdGlvbiksXSwKICAgICAgICAgICAgICAgICAgIGV4cHRociA9IDAuMywgbWluY3QgPSAyKQpwbG90X2RmID0gcGxvdF9kZlshKHBsb3RfZGYkaW50bHIgJWluJSBjKGRldmRmJGludGxyLCBlY21kZiRpbnRscikpLF0KaW1tX3BsdCA9IHBsdEZ1bmMocGxvdF9kZikKcGRmKCJmaWd1cmVfcGFuZWxzX3JldjEvZmlnX2NvbW0vbWFpbkZpZ19pbW11bmVOZXRJbnRlcmFjdC5wZGYiLCBoZWlnaHQgPSAyLjg2LCB3aWR0aCA9IDcuMSkKcHJpbnQoaW1tX3BsdCkKZGV2Lm9mZigpCmBgYAoKSGVhdG1hcHMgd2l0aCBudW1iZXIgb2YgaW50ZXJhY3Rpb25zIHBlciBjb25kaXRpb24KCmBgYHtyfQpjbnRzX2xpc3QgPSBsaXN0KCkKdGFiX2xpc3QgPSBsaXN0KCkKZm9yKG4gaW4gbmFtZXMoaW50ZXJfZGYpWzE6M10pewogIHN1YmRmY3QgPSB1bmlxdWUoaW50ZXJfZGZbW25dXVssMTozXSkKICBzdWJkZmN0JGN0MVtncmVwbCgiTFNFQ18iLCBzdWJkZmN0JGN0MSldID0gIkxTRUMiCiAgc3ViZGZjdCRjdDJbZ3JlcGwoIkxTRUNfIiwgc3ViZGZjdCRjdDIpXSA9ICJMU0VDIgogIHN1YmRmY3QkY3QxW2dyZXBsKCJIZXBhdCIsIHN1YmRmY3QkY3QxKV0gPSAiSGVwYXRvY3l0ZXMiCiAgc3ViZGZjdCRjdDJbZ3JlcGwoIkhlcGF0Iiwgc3ViZGZjdCRjdDIpXSA9ICJIZXBhdG9jeXRlcyIKICAjc3ViZGZjdCRjdDFbZ3JlcGwoIm5vbi0iLCBzdWJkZmN0JGN0MSldID0gIkVuZG90aGVsaWFsIGNlbGxzXG4obm9uLUxTRUMpIgogICNzdWJkZmN0JGN0MltncmVwbCgibm9uLSIsIHN1YmRmY3QkY3QyKV0gPSAiRW5kb3RoZWxpYWwgY2VsbHNcbihub24tTFNFQykiCiAgc3ViZGZjdCA9IHVuaXF1ZShzdWJkZmN0KQogIGRmY3QgPSB0YWJsZShkYXRhLmZyYW1lKCJjdDEiID0gYyhzdWJkZmN0JGN0MSwgc3ViZGZjdCRjdDIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICJjdDIiID0gYyhzdWJkZmN0JGN0Miwgc3ViZGZjdCRjdDEpKSkKICBoY2wgPSBoY2x1c3QoZGlzdChkZmN0KSwgbWV0aG9kID0gIndhcmQuRDIiKQogIHBsb3RfZGYgPSBkYXRhLmZyYW1lKGRmY3QpCiAgcGxvdF9kZiRjdDEgPSBmYWN0b3IocGxvdF9kZiRjdDEsIGxldmVscyA9IGxldmVscyhuZXRfbmFtZXNfYWxsJFZhcjEpKQogIHBsb3RfZGYkY3QyID0gZmFjdG9yKHBsb3RfZGYkY3QyLCBsZXZlbHMgPSBsZXZlbHMobmV0X25hbWVzX2FsbCRWYXIxKSkKICAjcGxvdF9kZiRjdDEgPSBmYWN0b3IocGxvdF9kZiRjdDEsIGxldmVscyA9IHJldihjKCJTdGVsbGF0ZSBjZWxscyIsICJMU0VDIiwgIkVuZG90aGVsaWFsIGNlbGxzXG4obm9uLUxTRUMpIiwKICAjICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJLdXBmZmVyIGNlbGxzIiwgImNEQ3MiLCAiTWFjcm9waGFnZXMiLCAiQ2hvbGFuZ2lvY3l0ZXMiLAogICMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInBEQ3MiLCAiYWItVCBjZWxscyIsICJIZXBhdG9jeXRlcyIsICJnZC1UIGNlbGxzIiwgCiAgIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiQiBjZWxscyIsICJQbGFzbWFibGFzdHMiKSkpCiAgI3Bsb3RfZGYkY3QyID0gZmFjdG9yKHBsb3RfZGYkY3QyLCBsZXZlbHMgPSByZXYoYygiU3RlbGxhdGUgY2VsbHMiLCAiTFNFQyIsICJFbmRvdGhlbGlhbCBjZWxsc1xuKG5vbi1MU0VDKSIsCiAgIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiS3VwZmZlciBjZWxscyIsICJjRENzIiwgIk1hY3JvcGhhZ2VzIiwgIkNob2xhbmdpb2N5dGVzIiwKICAjICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJwRENzIiwgImFiLVQgY2VsbHMiLCAiSGVwYXRvY3l0ZXMiLCAiZ2QtVCBjZWxscyIsIAogICMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkIgY2VsbHMiLCAiUGxhc21hYmxhc3RzIikpKQogIHBsdGNudHMgPSBnZ3Bsb3QocGxvdF9kZiwgYWVzKHggPSBjdDEsIHkgPSBjdDIsIHNpemUgPSBGcmVxLCBjb2xvdXIgPSBGcmVxKSkrCiAgICBnZW9tX3BvaW50KCkrCiAgICBsYWJzKHggPSAiY2VsbCB0eXBlIiwgeSA9ICJjZWxsIHR5cGUiLCB0aXRsZSA9IG4pKwogICAgZ3VpZGVzKGNvbG91ciA9IGd1aWRlX2xlZ2VuZCh0aXRsZSA9ICIjIGludGVyYWN0aW9ucyIsIHJldmVyc2UgPSBUKSwgCiAgICAgICAgICAgc2l6ZSA9IGd1aWRlX2xlZ2VuZCh0aXRsZSA9ICIjIGludGVyYWN0aW9ucyIsIHJldmVyc2UgPSBUKSkrCiAgICBzY2FsZV9jb2xvdXJfZ3JhZGllbnRuKGNvbG9ycyA9IGMoIiNlZGVkZWQiLCAiI2RlZWJmNyIsICIjOWVjYWUxIiwgIiNiY2JkZGMiLCAiIzc1NmJiMSIpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgbGltaXRzID0gYygwLCAyNDApKSsKICAgIHNjYWxlX3NpemVfY29udGludW91cyhsaW1pdHMgPSBjKDAsIDI0MCkpKwogICAgdGhlbWVfY2xhc3NpYygpKwogICAgdGhlbWUoYXNwZWN0LnJhdGlvID0gMSwKICAgICAgICAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoY29sb3VyID0gImJsYWNrIiksCiAgICAgICAgICBheGlzLmxpbmUgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCBoanVzdCA9IDEsIHZqdXN0ID0gMC40KSwKICAgICAgICAgIGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dChjb2xvdXIgPSAiYmxhY2siKSkKICBjbnRzX2xpc3RbW25dXSA9IHBsdGNudHMKICB0YWJfbGlzdFtbbl1dID0gZGZjdAp9CmNudHNfbGlzdCRsZWdlbmQgPSBjb3dwbG90OjpnZXRfbGVnZW5kKGNudHNfbGlzdCRoZWFsdGh5KQpjbnRzX2xpc3QkaGVhbHRoeSA9IGNudHNfbGlzdCRoZWFsdGh5K3RoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikKY250c19saXN0JGVtYm9saXNlZCA9IGNudHNfbGlzdCRlbWJvbGlzZWQrdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQpjbnRzX2xpc3QkcmVnZW5lcmF0aW5nID0gY250c19saXN0JHJlZ2VuZXJhdGluZyt0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpCgpwZGYoImZpZ3VyZV9wYW5lbHNfcmV2MS9maWdfY29tbS9zdXBwRmlnX2NvdW50c0NvbmQucGRmIiwgaGVpZ2h0ID0gMTUsIHdpZHRoID0gMTUpCmNudHNfbGlzdFtbMV1dK2NudHNfbGlzdFtbM11dK2NudHNfbGlzdFtbMl1dK2NudHNfbGlzdFtbNF1dKyAgICAgIHBhdGNod29yazo6cGxvdF9sYXlvdXQobmNvbCA9IDIpCmRldi5vZmYoKQpgYGAKCkhlYXRtYXBzIHdpdGggZGlmZmVyZW5jZSBpbiBudW1iZXIgb2YgaW50ZXJhY3Rpb25zIHZzIGhlYWx0aHkKCmBgYHtyfQpkaWZmX2NudF9sID0gbGlzdCgpCmZvcihuIGluIGMoImVtYm9saXNlZCIsICJyZWdlbmVyYXRpbmciKSl7CiAgZGlmX2RmID0gdGFiX2xpc3RbW25dXS10YWJfbGlzdCRoZWFsdGh5CiAgaGNsID0gaGNsdXN0KGRpc3QoZGlmX2RmKSwgbWV0aG9kID0gIndhcmQuRDIiKQogIHBsb3RfZGYgPSBkYXRhLmZyYW1lKGRpZl9kZikKICAjcGxvdF9kZiRjdDEgPSBmYWN0b3IocGxvdF9kZiRjdDEsIGxldmVscyA9IGxldmVscyhwbG90X2RmJGN0MSlbaGNsJG9yZGVyXSkKICAjcGxvdF9kZiRjdDIgPSBmYWN0b3IocGxvdF9kZiRjdDIsIGxldmVscyA9IGxldmVscyhwbG90X2RmJGN0MilbaGNsJG9yZGVyXSkKICBwbG90X2RmJGN0MSA9IGZhY3RvcihwbG90X2RmJGN0MSwgbGV2ZWxzID0gbGV2ZWxzKG5ldF9uYW1lc19hbGwkVmFyMSkpCiAgcGxvdF9kZiRjdDIgPSBmYWN0b3IocGxvdF9kZiRjdDIsIGxldmVscyA9IGxldmVscyhuZXRfbmFtZXNfYWxsJFZhcjEpKQogICNwbG90X2RmJGN0MSA9IGZhY3RvcihwbG90X2RmJGN0MSwgbGV2ZWxzID0gcmV2KGMoIlN0ZWxsYXRlIGNlbGxzIiwgIkxTRUMiLCAiRW5kb3RoZWxpYWwgY2VsbHNcbihub24tTFNFQykiLAogICMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkt1cGZmZXIgY2VsbHMiLCAiY0RDcyIsICJNYWNyb3BoYWdlcyIsICJDaG9sYW5naW9jeXRlcyIsCiAgIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicERDcyIsICJhYi1UIGNlbGxzIiwgIkhlcGF0b2N5dGVzIiwgImdkLVQgY2VsbHMiLCAKICAjICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJCIGNlbGxzIiwgIlBsYXNtYWJsYXN0cyIpKSkKICAjcGxvdF9kZiRjdDIgPSBmYWN0b3IocGxvdF9kZiRjdDIsIGxldmVscyA9IHJldihjKCJTdGVsbGF0ZSBjZWxscyIsICJMU0VDIiwgIkVuZG90aGVsaWFsIGNlbGxzXG4obm9uLUxTRUMpIiwKICAjICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJLdXBmZmVyIGNlbGxzIiwgImNEQ3MiLCAiTWFjcm9waGFnZXMiLCAiQ2hvbGFuZ2lvY3l0ZXMiLAogICMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInBEQ3MiLCAiYWItVCBjZWxscyIsICJIZXBhdG9jeXRlcyIsICJnZC1UIGNlbGxzIiwgCiAgIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiQiBjZWxscyIsICJQbGFzbWFibGFzdHMiKSkpCiAgcGx0Y250cyA9IGdncGxvdChwbG90X2RmW29yZGVyKHBsb3RfZGYkRnJlcSwgZGVjcmVhc2luZyA9IEYpLF0sIAogICAgICAgICAgICAgICAgICAgYWVzKHggPSBjdDEsIHkgPSBjdDIsIHNpemUgPSBhYnMoRnJlcSksIGNvbG91ciA9IEZyZXEpKSsKICAgIGdlb21fcG9pbnQoKSsKICAgIGxhYnMoeCA9ICJjZWxsIHR5cGUiLCB5ID0gImNlbGwgdHlwZSIsIHRpdGxlID0gcGFzdGUwKG4sICIgLSBoZWFsdGh5IikpKwogICAgZ3VpZGVzKGNvbG91ciA9IGd1aWRlX2xlZ2VuZCh0aXRsZSA9ICJjaGFuZ2UgaW5cbiMgaW50ZXJhY3Rpb25zIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJldmVyc2UgPSBULCBvdmVycmlkZS5hZXMgPSBsaXN0KHNpemUgPSA0KSksIAogICAgICAgICAgIHNpemUgPSBndWlkZV9ub25lKCkpKwogICAgc2NhbGVfY29sb3VyX2dyYWRpZW50bihjb2xvcnMgPSBjKCIjZDcxOTFjIiwgIiNmZGFlNjEiLCAiI2VkZWRlZCIsICIjYzJhNWNmIiwgIiM3YjMyOTQiKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGxpbWl0cyA9IGMoLTExMCwgMTEwKSkrCiAgICBzY2FsZV9zaXplX2NvbnRpbnVvdXMocmFuZ2UgPSBjKDAuMiwgNSkpKwogICAgdGhlbWVfY2xhc3NpYygpKwogICAgdGhlbWUoYXNwZWN0LnJhdGlvID0gMSwKICAgICAgICAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoY29sb3VyID0gImJsYWNrIiksCiAgICAgICAgICBheGlzLmxpbmUgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCBoanVzdCA9IDEsIHZqdXN0ID0gMC40KSwKICAgICAgICAgIGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dChjb2xvdXIgPSAiYmxhY2siLCBzaXplID0gOCkpCiAgcHJpbnQocGx0Y250cykKICBkaWZmX2NudF9sW1tuXV0gPSBwbHRjbnRzCn0KZGlmZl9jbnRfbCRsZWdlbmQgPSBjb3dwbG90OjpnZXRfbGVnZW5kKGRpZmZfY250X2wkZW1ib2xpc2VkKQpkaWZmX2NudF9sJGVtYm9saXNlZCA9IGRpZmZfY250X2wkZW1ib2xpc2VkK3RoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikKZGlmZl9jbnRfbCRyZWdlbmVyYXRpbmcgPSBkaWZmX2NudF9sJHJlZ2VuZXJhdGluZyt0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpCgpwZGYoImZpZ3VyZV9wYW5lbHNfcmV2MS9maWdfY29tbS9zdXBwRmlnX2NvdW50c0RpZmYucGRmIiwgaGVpZ2h0ID0gOCwgd2lkdGggPSAxNSkKcHJpbnQoY293cGxvdDo6cGxvdF9ncmlkKHBsb3RsaXN0ID0gZGlmZl9jbnRfbFtjKDIsMSwzKV0sIG5jb2wgPSAzLCByZWxfd2lkdGhzID0gYygxLDEsMC4zKSwgYWxpZ24gPSAiaCIpKQpkZXYub2ZmKCkKYGBgCgpIZWF0bWFwcyBieSBtaWQgY2VsbCB0eXBlCgpgYGB7cn0KbWF0Y2hfZGYgPSB1bmlxdWUoZGF0YS5mcmFtZSgiY3QiID0gYyhwb2ludF9jb25kX3VtYXBfZGYkY3QsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJNaWR6b25hbCBMU0VDIiwgIlBlcmljZW50cmFsIExTRUMiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiSWdHKyBQbGFzbWEgY2VsbHMiLCAiVFJNIGNlbGxzIiwgIkNEOCBhYi1UIGNlbGxzIDMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJIZXBhdG9jeXRlc19aMSIsIkhlcGF0b2N5dGVzX1oyIiwiSGVwYXRvY3l0ZXNfWjMiKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiY3RfbWlkIiA9IGMocG9pbnRfY29uZF91bWFwX2RmJGN0X21pZCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkxTRUMiLCAiTFNFQyIsIkIgY2VsbHMiLCAiVCBjZWxscyIsICJUIGNlbGxzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkhlcGF0b2N5dGVzIiwiSGVwYXRvY3l0ZXMiLCJIZXBhdG9jeXRlcyIpKSkKcm93bmFtZXMobWF0Y2hfZGYpID0gbWF0Y2hfZGYkY3QKCiMgaGVhdG1hcHMgYnkgbWlkIGNlbGwgdHlwZT8KY250c19saXN0ID0gbGlzdCgpCnRhYl9saXN0ID0gbGlzdCgpCmZvcihuIGluIG5hbWVzKGludGVyX2RmKVsxOjNdKXsKICBzdWJkZmN0ID0gdW5pcXVlKGludGVyX2RmW1tuXV1bLDE6M10pCiAgc3ViZGZjdCRjdDFbZ3JlcGwoIkhlcGF0Iiwgc3ViZGZjdCRjdDEpXSA9ICJIZXBhdG9jeXRlcyIKICBzdWJkZmN0JGN0MltncmVwbCgiSGVwYXQiLCBzdWJkZmN0JGN0MildID0gIkhlcGF0b2N5dGVzIgogIHN1YmRmY3QkbWlkX2N0MSA9IG1hdGNoX2RmW3N1YmRmY3QkY3QxLCAiY3RfbWlkIl0KICBzdWJkZmN0JG1pZF9jdDIgPSBtYXRjaF9kZltzdWJkZmN0JGN0MiwgImN0X21pZCJdCgogIHN1YmRmY3QgPSB1bmlxdWUoc3ViZGZjdFssYygxLDQ6NSldKQogIGRmY3QgPSB0YWJsZShkYXRhLmZyYW1lKCJjdDEiID0gYyhzdWJkZmN0JG1pZF9jdDEsIHN1YmRmY3QkbWlkX2N0MiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgImN0MiIgPSBjKHN1YmRmY3QkbWlkX2N0Miwgc3ViZGZjdCRtaWRfY3QxKSkpCiAgaGNsID0gaGNsdXN0KGRpc3QoZGZjdCksIG1ldGhvZCA9ICJ3YXJkLkQyIikKICBwbG90X2RmID0gZGF0YS5mcmFtZShkZmN0KQogIHBsb3RfZGYkY3QxID0gZmFjdG9yKHBsb3RfZGYkY3QxLCBsZXZlbHMgPSBoY2wkbGFiZWxzW2hjbCRvcmRlcl0pCiAgcGxvdF9kZiRjdDIgPSBmYWN0b3IocGxvdF9kZiRjdDIsIGxldmVscyA9IGhjbCRsYWJlbHNbaGNsJG9yZGVyXSkKICAKICBwbHRjbnRzID0gZ2dwbG90KHBsb3RfZGZbb3JkZXIocGxvdF9kZiRGcmVxLCBkZWNyZWFzaW5nID0gRiksXSwgCiAgICAgICAgICAgICAgICAgICBhZXMoeCA9IGN0MSwgeSA9IGN0Miwgc2l6ZSA9IEZyZXEsIGNvbG91ciA9IEZyZXEpKSsKICAgIGdlb21fcG9pbnQoKSsKICAgIGxhYnMoeCA9ICJjZWxsIHR5cGUiLCB5ID0gImNlbGwgdHlwZSIsIHRpdGxlID0gbikrCiAgICBndWlkZXMoY29sb3VyID0gZ3VpZGVfbGVnZW5kKHRpdGxlID0gIiMgaW50ZXJhY3Rpb25zIiwgcmV2ZXJzZSA9IFQpLCAKICAgICAgICAgICBzaXplID0gZ3VpZGVfbGVnZW5kKHRpdGxlID0gIiMgaW50ZXJhY3Rpb25zIiwgcmV2ZXJzZSA9IFQpKSsKICAgIHNjYWxlX2NvbG91cl9ncmFkaWVudG4oY29sb3JzID0gYygiI2VkZWRlZCIsICIjZGVlYmY3IiwgIiM5ZWNhZTEiLCAiI2JjYmRkYyIsICIjNzU2YmIxIiksIAogICAgICAgICAgICAgICAgICAgICAgICAgICBsaW1pdHMgPSBjKDAsIDMyMCkpKwogICAgc2NhbGVfc2l6ZV9jb250aW51b3VzKGxpbWl0cyA9IGMoMCwgMzIwKSkrCiAgICB0aGVtZV9jbGFzc2ljKCkrCiAgICB0aGVtZShhc3BlY3QucmF0aW8gPSAxLAogICAgICAgICAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChjb2xvdXIgPSAiYmxhY2siKSwKICAgICAgICAgIGF4aXMubGluZSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIGhqdXN0ID0gMSwgdmp1c3QgPSAwLjQpLAogICAgICAgICAgYXhpcy50ZXh0ID0gZWxlbWVudF90ZXh0KGNvbG91ciA9ICJibGFjayIpKQogIGNudHNfbGlzdFtbbl1dID0gcGx0Y250cwogIHRhYl9saXN0W1tuXV0gPSBkZmN0Cn0KY250c19saXN0JGxlZ2VuZCA9IGNvd3Bsb3Q6OmdldF9sZWdlbmQoY250c19saXN0JGhlYWx0aHkpCmNudHNfbGlzdCRoZWFsdGh5ID0gY250c19saXN0JGhlYWx0aHkrdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQpjbnRzX2xpc3QkZW1ib2xpc2VkID0gY250c19saXN0JGVtYm9saXNlZCt0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpCmNudHNfbGlzdCRyZWdlbmVyYXRpbmcgPSBjbnRzX2xpc3QkcmVnZW5lcmF0aW5nK3RoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikKCnBkZigiZmlndXJlX3BhbmVsc19yZXYxL2ZpZ19jb21tL3N1cHBGaWdfY291bnRzQ29uZF9taWQucGRmIiwgaGVpZ2h0ID0gNi45LCB3aWR0aCA9IDYuOSkKY250c19saXN0W1sxXV0rY250c19saXN0W1szXV0rY250c19saXN0W1syXV0rY250c19saXN0W1s0XV0rICAgICAgcGF0Y2h3b3JrOjpwbG90X2xheW91dChuY29sID0gMikKZGV2Lm9mZigpCmBgYAoKYGBge3J9CmRpZmZfY250X2wgPSBsaXN0KCkKZm9yKG4gaW4gYygiZW1ib2xpc2VkIiwgInJlZ2VuZXJhdGluZyIpKXsKICBkaWZfZGYgPSB0YWJfbGlzdFtbbl1dLXRhYl9saXN0JGhlYWx0aHkKICBoY2wgPSBoY2x1c3QoZGlzdChkaWZfZGYpLCBtZXRob2QgPSAid2FyZC5EMiIpCiAgcGxvdF9kZiA9IGRhdGEuZnJhbWUoZGlmX2RmKQogIHBsb3RfZGYkY3QxID0gZmFjdG9yKHBsb3RfZGYkY3QxLCBsZXZlbHMgPSBsZXZlbHMocGxvdF9kZiRjdDEpW2hjbCRvcmRlcl0pCiAgcGxvdF9kZiRjdDIgPSBmYWN0b3IocGxvdF9kZiRjdDIsIGxldmVscyA9IGxldmVscyhwbG90X2RmJGN0MilbaGNsJG9yZGVyXSkKCiAgcGx0Y250cyA9IGdncGxvdChwbG90X2RmW29yZGVyKHBsb3RfZGYkRnJlcSwgZGVjcmVhc2luZyA9IEYpLF0sIAogICAgICAgICAgICAgICAgICAgYWVzKHggPSBjdDEsIHkgPSBjdDIsIHNpemUgPSBhYnMoRnJlcSksIGNvbG91ciA9IEZyZXEpKSsKICAgIGdlb21fcG9pbnQoKSsKICAgIGxhYnMoeCA9ICJjZWxsIHR5cGUiLCB5ID0gImNlbGwgdHlwZSIsIHRpdGxlID0gcGFzdGUwKG4sICIgLSBoZWFsdGh5IikpKwogICAgZ3VpZGVzKGNvbG91ciA9IGd1aWRlX2xlZ2VuZCh0aXRsZSA9ICJjaGFuZ2UgaW5cbiMgaW50ZXJhY3Rpb25zIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJldmVyc2UgPSBULCBvdmVycmlkZS5hZXMgPSBsaXN0KHNpemUgPSA0KSksIAogICAgICAgICAgIHNpemUgPSBndWlkZV9ub25lKCkpKwogICAgc2NhbGVfY29sb3VyX2dyYWRpZW50bihjb2xvcnMgPSBjKCIjZDcxOTFjIiwgIiNmZGFlNjEiLCAiI2VkZWRlZCIsICIjYzJhNWNmIiwgIiM3YjMyOTQiKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGxpbWl0cyA9IGMoLTE1MCwgMTUwKSkrCiAgICBzY2FsZV9zaXplX2NvbnRpbnVvdXMocmFuZ2UgPSBjKDAuMiwgNSkpKwogICAgdGhlbWVfY2xhc3NpYygpKwogICAgdGhlbWUoYXNwZWN0LnJhdGlvID0gMSwKICAgICAgICAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoY29sb3VyID0gImJsYWNrIiksCiAgICAgICAgICBheGlzLmxpbmUgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCBoanVzdCA9IDEsIHZqdXN0ID0gMC40KSwKICAgICAgICAgIGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dChjb2xvdXIgPSAiYmxhY2siLCBzaXplID0gOCkpCiAgcHJpbnQocGx0Y250cykKICBkaWZmX2NudF9sW1tuXV0gPSBwbHRjbnRzCn0KZGlmZl9jbnRfbCRsZWdlbmQgPSBjb3dwbG90OjpnZXRfbGVnZW5kKGRpZmZfY250X2wkZW1ib2xpc2VkKQpkaWZmX2NudF9sJGVtYm9saXNlZCA9IGRpZmZfY250X2wkZW1ib2xpc2VkK3RoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikKZGlmZl9jbnRfbCRyZWdlbmVyYXRpbmcgPSBkaWZmX2NudF9sJHJlZ2VuZXJhdGluZyt0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpCgpwZGYoImZpZ3VyZV9wYW5lbHNfcmV2MS9maWdfY29tbS9zdXBwRmlnX2NvdW50c0RpZmZfbWlkLnBkZiIsIGhlaWdodCA9IDMuNDUsIHdpZHRoID0gNi45KQpwcmludChjb3dwbG90OjpwbG90X2dyaWQocGxvdGxpc3QgPSBkaWZmX2NudF9sW2MoMiwxLDMpXSwgCiAgICAgICAgICAgICAgICAgICAgICAgICBuY29sID0gMywgcmVsX3dpZHRocyA9IGMoMSwxLDAuMyksIGFsaWduID0gImh2IikpCmRldi5vZmYoKQpgYGAKClVuaXF1ZSBpbnRlcmFjdGlvbnMgZnJvbSBFIGFuZCBSCgpgYGB7cn0KIyBudW1iZXIgb2YgbmV3IHVuaXF1ZSBpbnRlcmFjdGlvbnMKIyMgaS5lLiB0aGlzIGxpZ2FuZC1yZWNlcHRvciBwYWlyIHdhcyBhYnNlbnQgYXQgbGVhc3QgaW4gaGVhbHRoeSBhbmQgYWx3YXlzIGluY2x1ZGVzIHRoaXMgY3QKIyBnZXQgaW50ZXJhY3Rpb25zIHRoYXQgYXJlIG5vdCBpbiBoZWFsdGh5CmludGVyX2ggPSBpbnRlcl9kZiRoZWFsdGh5JGlkX2NwX2ludGVyYWN0aW9uCmludGVyX3JlZ19zdWIgPSBpbnRlcl9kZiRyZWdlbmVyYXRpbmdbIWludGVyX2RmJHJlZ2VuZXJhdGluZyRpZF9jcF9pbnRlcmFjdGlvbiAlaW4lIGludGVyX2gsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgMTozXQppbnRlcl9lbWJfc3ViID0gaW50ZXJfZGYkZW1ib2xpc2VkWyFpbnRlcl9kZiRlbWJvbGlzZWQkaWRfY3BfaW50ZXJhY3Rpb24gJWluJSBpbnRlcl9oLCAxOjNdCgpwdmVfaW50ZXIgPSByYmluZChpbnRlcl9yZWdfc3ViLCBpbnRlcl9lbWJfc3ViKQpwdmVfaW50ZXIkY29uZCA9IGMocmVwKCJyZWdlbmVyYXRpbmciLCBucm93KGludGVyX3JlZ19zdWIpKSwKICAgICAgICAgICAgICAgICAgIHJlcCgiZW1ib2xpc2VkIiwgbnJvdyhpbnRlcl9lbWJfc3ViKSkpCnB2ZV9pbnRlciRtaWRfY3QxID0gbWF0Y2hfZGZbcHZlX2ludGVyJGN0MSwiY3RfbWlkIl0KcHZlX2ludGVyJG1pZF9jdDIgPSBtYXRjaF9kZltwdmVfaW50ZXIkY3QyLCJjdF9taWQiXQoKIyBsaXN0IHVuaXF1ZSBpbnRlcmFjdGlvbnMgKGFsbCBjdCkKY3RfaW50ZXJfbCA9IGxpc3QoKQpmb3IoY29uZCBpbiB1bmlxdWUocHZlX2ludGVyJGNvbmQpKXsKICBjdF9pbnRlcl9sW1tjb25kXV0gPSBsaXN0KCkKICBzdWJfcHZlX2ludGVyID0gcHZlX2ludGVyW3B2ZV9pbnRlciRjb25kPT1jb25kLF0KICBzdWJfcHZlX2ludGVyID0gc3ViX3B2ZV9pbnRlcltzdWJfcHZlX2ludGVyJGN0MSE9c3ViX3B2ZV9pbnRlciRjdDIsXQogIAogIGludGVyX3UgPSB1bmlxdWUoc3ViX3B2ZV9pbnRlciRpZF9jcF9pbnRlcmFjdGlvbikKICBmb3IoaSBpbiBpbnRlcl91KXsKICAgIGlkZiA9IHN1Yl9wdmVfaW50ZXJbc3ViX3B2ZV9pbnRlciRpZF9jcF9pbnRlcmFjdGlvbj09aSwgYygiY3QxIiwgImN0MiIpXQogICAgdGFiX2ludF9udSA9IHRhYmxlKGlkZiRjdDEsIGlkZiRjdDIpCiAgICAKICAgIGlmKG5yb3codGFiX2ludF9udSk9PTEpewogICAgICBjdF9pbnRlcl9sW1tjb25kXV1bW2ldXSA9IHJvd25hbWVzKHRhYl9pbnRfbnUpCiAgICB9CiAgICBpZihuY29sKHRhYl9pbnRfbnUpPT0xKXsKICAgICAgY3RfaW50ZXJfbFtbY29uZF1dW1tpXV0gPSBjb2xuYW1lcyh0YWJfaW50X251KQogICAgfQogIH0KICAKfQpjdF9pbnRlcl9sID0gcmVzaGFwZTI6Om1lbHQoY3RfaW50ZXJfbCkKdGFibGUoY3RfaW50ZXJfbCR2YWx1ZSwgY3RfaW50ZXJfbCRMMSkKCiMgbGlzdCB1bmlxdWUgaW50ZXJhY3Rpb25zIChtaWQgY3QpCmN0bWlkX2ludGVyX2wgPSBsaXN0KCkKY3RtaWRfaW50ZXJfbF9jdCA9IGxpc3QoKQpmb3IoY29uZCBpbiB1bmlxdWUocHZlX2ludGVyJGNvbmQpKXsKICBjdG1pZF9pbnRlcl9sW1tjb25kXV0gPSBsaXN0KCkKICBjdG1pZF9pbnRlcl9sX2N0W1tjb25kXV0gPSBsaXN0KCkKICBzdWJfcHZlX2ludGVyID0gcHZlX2ludGVyW3B2ZV9pbnRlciRjb25kPT1jb25kLF0KICBzdWJfcHZlX2ludGVyID0gc3ViX3B2ZV9pbnRlcltzdWJfcHZlX2ludGVyJG1pZF9jdDEhPXN1Yl9wdmVfaW50ZXIkbWlkX2N0MixdCiAgCiAgaW50ZXJfdSA9IHVuaXF1ZShzdWJfcHZlX2ludGVyJGlkX2NwX2ludGVyYWN0aW9uKQogIGZvcihpIGluIGludGVyX3UpewogICAgaWRmID0gc3ViX3B2ZV9pbnRlcltzdWJfcHZlX2ludGVyJGlkX2NwX2ludGVyYWN0aW9uPT1pLCBjKCJtaWRfY3QxIiwgIm1pZF9jdDIiKV0KICAgIHRhYl9pbnRfbnUgPSB0YWJsZShpZGYkbWlkX2N0MSwgaWRmJG1pZF9jdDIpCiAgICBtaWRfY3QxX2N0ID0gc3ViX3B2ZV9pbnRlcltzdWJfcHZlX2ludGVyJGlkX2NwX2ludGVyYWN0aW9uPT1pLCAiY3QxIl0KICAgIG1pZF9jdDJfY3QgPSBzdWJfcHZlX2ludGVyW3N1Yl9wdmVfaW50ZXIkaWRfY3BfaW50ZXJhY3Rpb249PWksICJjdDIiXQogICAgCiAgICBpZihucm93KHRhYl9pbnRfbnUpPT0xKXsKICAgICAgY3RtaWRfaW50ZXJfbFtbY29uZF1dW1tpXV0gPSByb3duYW1lcyh0YWJfaW50X251KQogICAgICBjdG1pZF9pbnRlcl9sX2N0W1tjb25kXV1bW2ldXSA9IG1pZF9jdDFfY3QKICAgIH0KICAgIGlmKG5jb2wodGFiX2ludF9udSk9PTEpewogICAgICBjdG1pZF9pbnRlcl9sW1tjb25kXV1bW2ldXSA9IGNvbG5hbWVzKHRhYl9pbnRfbnUpCiAgICAgIGN0bWlkX2ludGVyX2xfY3RbW2NvbmRdXVtbaV1dID0gbWlkX2N0Ml9jdAogICAgfQogIH0KICAKfQpjdG1pZF9pbnRlcl9sID0gcmVzaGFwZTI6Om1lbHQoY3RtaWRfaW50ZXJfbCkKY3RtaWRfaW50ZXJfbF9jdCA9IHVuaXF1ZShyZXNoYXBlMjo6bWVsdChjdG1pZF9pbnRlcl9sX2N0KSkKY3RtaWRfaW50ZXJfbCA9IG1lcmdlKGN0bWlkX2ludGVyX2wsIGN0bWlkX2ludGVyX2xfY3QsIGJ5ID0gYygiTDIiLCAiTDEiKSwgCiAgICAgICAgICAgICAgICAgICAgICBhbGwgPSBUKVssYygzLDEsMiw0KV0KdGFibGUoY3RtaWRfaW50ZXJfbCR2YWx1ZS54LCBjdG1pZF9pbnRlcl9sJEwxKQpgYGAKCkZ1bmN0aW9ucyB0byBwbG90IGludGVyYWN0aW9ucwoKYGBge3J9CmZpbHRGdW5jVSA9IGZ1bmN0aW9uKHgsIGludGRmLCBtdXR0aHIgPSAwLCBleHB0aHIgPSAwLjEyLCBtaW5jdCA9IDMpewogIGNvbGRmID0geFssMTo4XQogICNpbnRfY3RfcF90ID0gcGFzdGUwKGludGRmJHZhbHVlLCBpbnRkZiRMMikKICBjb2xkZiRpc01haW4xID0gYXBwbHkoY29sZGYsIDEsIGZ1bmN0aW9uKHkpIHBhc3RlMCh5WzJdLCB5WzFdKSAlaW4lIGludGRmKQogIGNvbGRmJGlzTWFpbjIgPSBhcHBseShjb2xkZiwgMSwgZnVuY3Rpb24oeSkgcGFzdGUwKHlbM10sIHlbMV0pICVpbiUgaW50ZGYpCiAgCiAgIyBzd2FwIGlmIGlzTWFpbjIKICBmb3IoaSBpbiAxOm5yb3coY29sZGYpKXsKICAgIGlmKGNvbGRmW2ksImlzTWFpbjIiXSl7CiAgICAgIHRtcGN0ID0gY29sZGZbaSwiY3QyIl0KICAgICAgdG1wbHIgPSBjb2xkZltpLCJscjIiXQogICAgICB0bXBtYSA9IGNvbGRmW2ksImlzTWFpbjIiXQogICAgICAKICAgICAgY29sZGZbaSwiY3QyIl0gPSBjb2xkZltpLCJjdDEiXQogICAgICBjb2xkZltpLCJscjIiXSA9IGNvbGRmW2ksImxyMSJdCiAgICAgIGNvbGRmW2ksImlzTWFpbjIiXSA9IGNvbGRmW2ksImlzTWFpbjEiXQogICAgICAKICAgICAgY29sZGZbaSwiY3QxIl0gPSB0bXBjdAogICAgICBjb2xkZltpLCJscjEiXSA9IHRtcGxyCiAgICAgIGNvbGRmW2ksImlzTWFpbjEiXSA9IHRtcG1hCiAgICB9CiAgfQoKICAjIGludGVyYWN0aW9uIG5hbWVzCiAgY29sZGYkaW50bHIgPSBwYXN0ZTAoY29sZGYkbHIxLCAiIC1cbiAiLCBjb2xkZiRscjIpCiAgY29sZGYgPSB1bmlxdWUoY29sZGZbLGMoMiwzLDExLDY6MTApXSkKICAjIGludGVyYWN0aW9uIGZyZXF1ZW5jeQogIG5pbnQgPSB0YWJsZShjb2xkZiRpbnRscikKICAjIGV4cHJlc3Npb24gYW5kIGludGVyYWN0aW9uIGZpbHRlcmluZwogIGNvbGRmID0gY29sZGZbYXBwbHkoY29sZGZbLDQ6Nl0sIDEsIGZ1bmN0aW9uKHgpIGFueSh4Pj1leHB0aHIpKSAmIAogICAgICAgICAgICAgICAgICAoY29sZGYkaW50bHIgJWluJSBuYW1lcyhuaW50KVtuaW50PjFdIHwgCiAgICAgICAgICAgICAgICAgICAgIGFwcGx5KGNvbGRmWyw0OjZdLCAxLCBmdW5jdGlvbih4KSBhbnkoeD49ZXhwdGhyKjgpKSksXQogICMgcmVzaGFwaW5nIGZvciBwbG90CiAgY29sZGYgPSBkYXRhLnRhYmxlOjpyYmluZGxpc3QobGlzdChyZXNoYXBlMjo6bWVsdChjb2xkZlssYygzLDEsNDo3KV0pLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlc2hhcGUyOjptZWx0KGNvbGRmWyxjKDMsMiw0OjYsIDgpXSkpLCB1c2UubmFtZXMgPSBGKQogIGNvbGRmJHZhcmlhYmxlID0gdW5saXN0KGxhcHBseShzdHJzcGxpdChhcy5jaGFyYWN0ZXIoY29sZGYkdmFyaWFibGUpLCAiXyIpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZnVuY3Rpb24oeCkgeFsxXSkpCiAgY29sZGYkdmFyaWFibGUgPSBmYWN0b3IoY29sZGYkdmFyaWFibGUsIGxldmVscyA9IGMoImhlYWx0aHkiLCJyZWdlbmVyYXRpbmciLCAiZW1ib2xpc2VkIikpCiAgY29sZGYgPSBjb2xkZltvcmRlcihjb2xkZiR2YWx1ZSwgZGVjcmVhc2luZyA9IFQpLF0KICBjb2xkZiA9IGNvbGRmWyFkdXBsaWNhdGVkKGNvbGRmWywxOjRdKSxdCiAgY29sZGYkY3QxID0gZ3N1YigiRW5kb3RoZWxpYWwgY2VsbHMiLCAiRUMiLCBjb2xkZiRjdDEpCiAgY29sZGYkaW50bHIgPSBnc3ViKCJyZWNlcHRvciIsICJyZWMiLCBjb2xkZiRpbnRscikKICBjb2xkZiRpbnRsciA9IGdzdWIoImNvbXBsZXgiLCAiY29tcCIsIGNvbGRmJGludGxyKQogIG5jdCA9IHRhYmxlKGNvbGRmJGN0MSkKICBjb2xkZiA9IGNvbGRmW2NvbGRmJGN0MSAlaW4lIG5hbWVzKG5jdClbbmN0Pj1taW5jdCozXSxdCiAgbmludCA9IHRhYmxlKGNvbGRmJGludGxyKQogIGNvbGRmID0gY29sZGZbY29sZGYkaW50bHIgJWluJSBuYW1lcyhuaW50KVtuaW50PjNdLF0KICAKICAjIGNvbmZpcm0gdGhhdCBhbGwgaW50ZXJhY3Rpb25zIGhhdmUgYXQgbGVhc3Qgb25lIFRSVUUKICBudHJ1ZSA9IHRhcHBseShjb2xkZiRpc01haW4xLCBjb2xkZiRpbnRsciwgc3VtKQogIGNvbGRmID0gY29sZGZbY29sZGYkaW50bHIgJWluJSBuYW1lcyhudHJ1ZSlbbnRydWU+MF1dCiAgCiAgIyBmb3JtYXR0aW5nCiAgY29sZGYgPSBjb2xkZltvcmRlcihjb2xkZiRpc01haW4xLCBjb2xkZiRpbnRsciwgLWNvbGRmJHZhbHVlLCBkZWNyZWFzaW5nID0gVCksXQogIGNvbGRmJGN0MSA9IGZhY3Rvcihjb2xkZiRjdDEsIGxldmVscyA9IHJldih1bmlxdWUoY29sZGYkY3QxKSkpCiAgY29sZGYkaW50bHIgPSBmYWN0b3IoY29sZGYkaW50bHIsIGxldmVscyA9IHJldih1bmlxdWUoY29sZGYkaW50bHIpKSkKICBjb2xkZiA9IGNvbGRmW29yZGVyKGNvbGRmJGlzTWFpbjEsIGRlY3JlYXNpbmcgPSBGKSxdCiAgCiAgcmV0dXJuKGNvbGRmKQp9CgpwbHRGdW5jVSA9IGZ1bmN0aW9uKHgpewogIHBsdCA9IGdncGxvdCh4LCBhZXMoeSA9IGN0MSwgeCA9IHZhcmlhYmxlLCBmaWxsID0gdmFsdWUsIGNvbG91ciA9IGlzTWFpbjEpKSsKICAgIGZhY2V0X2dyaWQoaW50bHJ+Liwgc2NhbGVzID0gImZyZWVfeSIsIHNwYWNlID0gImZyZWVfeSIpKwogICAgZ2VvbV90aWxlKHNpemUgPSAwLjQpKwogICAgc2NhbGVfeF9kaXNjcmV0ZShleHBhbmQgPSBjKDAsMCkpKwogICAgc2NhbGVfZmlsbF9ncmFkaWVudG4oY29sb3JzID0gZ3JhZGV4cGNvbCkrCiAgICBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcyA9IGMoIndoaXRlIiwgImJsYWNrIikpKwogICAgZ3VpZGVzKGZpbGwgPSBndWlkZV9jb2xvdXJiYXIoYmFyaGVpZ2h0ID0gdW5pdCgwLjQsICJjbSIpKSwKICAgICAgICAgICBjb2xvdXIgPSBndWlkZV9ub25lKCkpKwogICAgbGFicyh4ID0gIkNvbmRpdGlvbiIsIHkgPSAiQ2VsbCB0eXBlIiwgZmlsbCA9ICJtZWFuIGV4cCIpKwogICAgdGhlbWVfY2xhc3NpYygpKwogICAgdGhlbWUoYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoY29sb3VyID0gImJsYWNrIiwgc2l6ZSA9IDcsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYW5nbGUgPSAwLCBoanVzdCA9IDEsIHZqdXN0ID0gMC41KSwKICAgICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGNvbG91ciA9ICJibGFjayIsIHNpemUgPSA2LjUsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYW5nbGUgPSAzNSwgaGp1c3Q9MSwgdmp1c3Q9MSksCiAgICAgICAgICBheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSA3KSwKICAgICAgICAgIGF4aXMubGluZSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iLAogICAgICAgICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSA3KSwKICAgICAgICAgIGxlZ2VuZC5ib3gubWFyZ2luID0gbWFyZ2luKDAsMCwwLDApLAogICAgICAgICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDYpLAogICAgICAgICAgc3RyaXAudGV4dC55ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gMCwgc2l6ZSA9IDcsIG1hcmdpbiA9IG1hcmdpbigwLDAsMywwKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaGp1c3QgPSAwLjUsIHZqdXN0ID0gMC41LCBmYWNlID0gImJvbGQiKSwKICAgICAgICAgIHN0cmlwLmJhY2tncm91bmQgPSBlbGVtZW50X2JsYW5rKCkpCiAgcmV0dXJuKHBsdCkKfQpgYGAKClBsb3QgYWxsCgpgYGB7cn0KcGxvdF9kZiA9IGZpbHRGdW5jVShoZXJfYWxsaW50X2ZbaGVyX2FsbGludF9mJGlkX2NwX2ludGVyYWN0aW9uICVpbiUgY3RfaW50ZXJfbCRMMlshZ3JlcGwoInN0cmVzcyIsIGN0X2ludGVyX2wkdmFsdWUpXSxdLAogICAgICAgICAgICAgICAgICAgIGludGRmID0gcGFzdGUwKGN0X2ludGVyX2wkdmFsdWUsIGN0X2ludGVyX2wkTDIpLCAKICAgICAgICAgICAgICAgICAgICBleHB0aHIgPSAwLjIsIG1pbmN0ID0gMSkKaW1tX3BsdCA9IHBsdEZ1bmNVKHBsb3RfZGYpCnBkZigiZmlndXJlX3BhbmVsc19yZXYxL2ZpZ19jb21tL21haW5GaWdfSW50ZXJhY3RVbmlxdWUucGRmIiwgCiAgICBoZWlnaHQgPSAyMCwgd2lkdGggPSAyLjgpCnByaW50KGltbV9wbHQpCmRldi5vZmYoKQoKcGxvdF9kZiA9IGZpbHRGdW5jVShoZXJfYWxsaW50X2ZbaGVyX2FsbGludF9mJGlkX2NwX2ludGVyYWN0aW9uICVpbiUgY3RtaWRfaW50ZXJfbCRMMlshZ3JlcGwoInN0cmVzcyIsIGN0bWlkX2ludGVyX2wkdmFsdWUueSldLF0sCiAgICAgICAgICAgICAgICAgICBpbnRkZiA9IHBhc3RlMChjdG1pZF9pbnRlcl9sJHZhbHVlLnksIGN0bWlkX2ludGVyX2wkTDIpLCAKICAgICAgICAgICAgICAgICAgIGV4cHRociA9IDAuMiwgbWluY3QgPSAzKQppbW1fcGx0ID0gcGx0RnVuY1UocGxvdF9kZikKcGRmKCJmaWd1cmVfcGFuZWxzX3JldjEvZmlnX2NvbW0vbWFpbkZpZ19JbnRlcmFjdFVuaXF1ZV9taWQucGRmIiwgCiAgICBoZWlnaHQgPSAzMiwgd2lkdGggPSAyLjgpCnByaW50KGltbV9wbHQpCmRldi5vZmYoKQpgYGAKClBsb3Qgb25lIGJ5IG9uZQoKYGBge3J9CnBsb3RfZGYgPSBmaWx0RnVuY1UoaGVyX2FsbGludF9mW2hlcl9hbGxpbnRfZiRpZF9jcF9pbnRlcmFjdGlvbiAlaW4lIGN0X2ludGVyX2wkTDJbIWdyZXBsKCJzdHJlc3MiLCBjdF9pbnRlcl9sJHZhbHVlKV0sXSwKICAgICAgICAgICAgICAgICAgICBpbnRkZiA9IHBhc3RlMChjdF9pbnRlcl9sJHZhbHVlLCBjdF9pbnRlcl9sJEwyKSwgCiAgICAgICAgICAgICAgICAgICAgZXhwdGhyID0gMC4yLCBtaW5jdCA9IDMpCgpmb2xkZXIgPSAiZmlndXJlX3BhbmVsc19yZXYxL2ZpZ19jb21tL2hlYXRtYXBzX2ludGVyYWN0X2luZGl2LyIKZm9yKGkgaW4gMTpsZW5ndGgodW5pcXVlKHBsb3RfZGYkaW50bHIpKSl7CiAgaWlpID0gdW5pcXVlKHBsb3RfZGYkaW50bHIpW2ldCiAgc3ViX3Bsb3RfZGYgPSBwbG90X2RmW3Bsb3RfZGYkaW50bHI9PWlpaSxdCiAgc3ViX3Bsb3RfZGYgPSBzdWJfcGxvdF9kZltvcmRlcihzdWJfcGxvdF9kZiRpc01haW4xLCBzdWJfcGxvdF9kZiR2YWx1ZSwgZGVjcmVhc2luZyA9IFQpLF0KICBzdWJfcGxvdF9kZiRjdDEgPSBmYWN0b3Ioc3ViX3Bsb3RfZGYkY3QxLCBsZXZlbHMgPSByZXYodW5pcXVlKHN1Yl9wbG90X2RmJGN0MSkpKQogIHN1Yl9wbG90X2RmID0gc3ViX3Bsb3RfZGZbb3JkZXIoc3ViX3Bsb3RfZGYkaXNNYWluMSwgZGVjcmVhc2luZyA9IEYpLF0KICAKICBwZGYocGFzdGUwKGZvbGRlciwgIm1haW5GaWdfSW50ZXJhY3RVbmlxdWVfIiwgaSwgIi5wZGYiKSwgaGVpZ2h0ID0gMywgd2lkdGggPSA0KQogIHByaW50KHBsdEZ1bmNVKHN1Yl9wbG90X2RmKSkKICBkZXYub2ZmKCkKfQoKcGxvdF9kZiA9IGZpbHRGdW5jVShoZXJfYWxsaW50X2ZbaGVyX2FsbGludF9mJGlkX2NwX2ludGVyYWN0aW9uICVpbiUgY3RtaWRfaW50ZXJfbCRMMlshZ3JlcGwoInN0cmVzcyIsIGN0bWlkX2ludGVyX2wkdmFsdWUueSldLF0sCiAgICAgICAgICAgICAgICAgICBpbnRkZiA9IHBhc3RlMChjdG1pZF9pbnRlcl9sJHZhbHVlLnksIGN0bWlkX2ludGVyX2wkTDIpLCAKICAgICAgICAgICAgICAgICAgIGV4cHRociA9IDAuMiwgbWluY3QgPSAzKQoKZm9sZGVyID0gImZpZ3VyZV9wYW5lbHNfcmV2MS9maWdfY29tbS9oZWF0bWFwc19pbnRlcmFjdF9pbmRpdi8iCmZvcihpIGluIDE6bGVuZ3RoKHVuaXF1ZShwbG90X2RmJGludGxyKSkpewogIGlpaSA9IHVuaXF1ZShwbG90X2RmJGludGxyKVtpXQogIHN1Yl9wbG90X2RmID0gcGxvdF9kZltwbG90X2RmJGludGxyPT1paWksXQogIHN1Yl9wbG90X2RmID0gc3ViX3Bsb3RfZGZbb3JkZXIoc3ViX3Bsb3RfZGYkaXNNYWluMSwgc3ViX3Bsb3RfZGYkdmFsdWUsIGRlY3JlYXNpbmcgPSBUKSxdCiAgc3ViX3Bsb3RfZGYkY3QxID0gZmFjdG9yKHN1Yl9wbG90X2RmJGN0MSwgbGV2ZWxzID0gcmV2KHVuaXF1ZShzdWJfcGxvdF9kZiRjdDEpKSkKICBzdWJfcGxvdF9kZiA9IHN1Yl9wbG90X2RmW29yZGVyKHN1Yl9wbG90X2RmJGlzTWFpbjEsIGRlY3JlYXNpbmcgPSBGKSxdCiAgCiAgcGRmKHBhc3RlMChmb2xkZXIsICJtYWluRmlnX0ludGVyYWN0VW5pcXVlX21pZF8iLCBpLCAiLnBkZiIpLCBoZWlnaHQgPSAzLCB3aWR0aCA9IDIuOCkKICBwcmludChwbHRGdW5jVShzdWJfcGxvdF9kZikpCiAgZGV2Lm9mZigpCn0KYGBgCgpQbG90IG9uZSBieSBvbmUsIGFsbCBpbiBIIHZzIFBWRSBuZXR3b3JrCgpgYGB7cn0KZWRnZV9taW4gPSBlZGdlX2NvbmRfZGZbLGMoMTo0LDk6MTIpXQplZGdlX21pbiA9IG1lcmdlKGVkZ2VfbWluLCB1bmlxdWUoaGVyX2FsbGludF9mWyxjKDEsMTMpXSksIGJ5LnggPSAzLCBieS55ID0gMSwgYWxsLnggPSBUKQplZGdlX21pbiA9IG1lcmdlKGVkZ2VfbWluLCB1bmlxdWUoaGVyX2FsbGludF9mWyxjKDEsMTcpXSksIGJ5LnggPSAxLCBieS55ID0gMSwgYWxsLnggPSBUKQplZGdlX21pbiA9IGVkZ2VfbWluW2VkZ2VfbWluJGN0X2cxIT1lZGdlX21pbiRjdF9nMixdCmVkZ2VfbWluID0gZWRnZV9taW5bZWRnZV9taW4kaWRfY3BfaW50ZXJhY3Rpb24gJWluJSBjb21waF9pbnRlcnMsXQoKcGxvdF9kZiA9IGZpbHRGdW5jKGhlcl9hbGxpbnRfZltoZXJfYWxsaW50X2YkaWRfY3BfaW50ZXJhY3Rpb24gJWluJSB1bmlxdWUoZWRnZV9taW4kaWRfY3BfaW50ZXJhY3Rpb24pLF0sCiAgICAgICAgICAgICAgICAgICBleHB0aHIgPSAwLjE1LCBtaW5jdCA9IDIpCiNpbW1fcGx0ID0gcGx0RnVuYyhwbG90X2RmKQojcGRmKCJmaWd1cmVfcGFuZWxzX3JldjEvZmlnX2NvbW0vdGVzdC5wZGYiLCB3aWR0aCA9IDUwLCBoZWlnaHQgPSAzKQojcHJpbnQoaW1tX3BsdCkKI2Rldi5vZmYoKQoKZm9sZGVyID0gImZpZ3VyZV9wYW5lbHNfcmV2MS9maWdfY29tbS9oZWF0bWFwc19pbnRlcmFjdF9pbmRpdl9ocHZlLyIKZm9yKGkgaW4gMTpsZW5ndGgodW5pcXVlKHBsb3RfZGYkaW50bHIpKSl7CiAgaWlpID0gdW5pcXVlKHBsb3RfZGYkaW50bHIpW2ldCiAgc3ViX3Bsb3RfZGYgPSBwbG90X2RmW3Bsb3RfZGYkaW50bHI9PWlpaSxdCiAgc3ViX3Bsb3RfZGYgPSBzdWJfcGxvdF9kZltvcmRlcihzdWJfcGxvdF9kZiR2YWx1ZSwgZGVjcmVhc2luZyA9IFQpLF0KICBzdWJfcGxvdF9kZiRjdDEgPSBmYWN0b3Ioc3ViX3Bsb3RfZGYkY3QxLCBsZXZlbHMgPSByZXYodW5pcXVlKHN1Yl9wbG90X2RmJGN0MSkpKQoKICBwZGYocGFzdGUwKGZvbGRlciwgIm1haW5GaWdfSW50ZXJhY3RIUFZFXyIsIGksICIucGRmIiksIGhlaWdodCA9IDMsIHdpZHRoID0gNCkKICBwcmludChwbHRGdW5jKHN1Yl9wbG90X2RmKSkKICBkZXYub2ZmKCkKfQpgYGAKClBsb3QgY2hhbmdlcyBpbiBudW1iZXIgb2YgaW50ZXJhY3Rpb25zIHBlciBjb25kaXRpb24gLSBtaWQgcmVzb2x1dGlvbgoKYGBge3J9Cm1hdGNoX2RmID0gdW5pcXVlKGRhdGEuZnJhbWUoImN0IiA9IGMocG9pbnRfY29uZF91bWFwX2RmJGN0LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiTWlkem9uYWwgTFNFQyIsICJQZXJpY2VudHJhbCBMU0VDIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIklnRysgUGxhc21hIGNlbGxzIiwgIlRSTSBjZWxscyIsICJDRDggYWItVCBjZWxscyAzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiSGVwYXRvY3l0ZXNfWjEiLCJIZXBhdG9jeXRlc19aMiIsIkhlcGF0b2N5dGVzX1ozIiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImN0X21pZCIgPSBjKHBvaW50X2NvbmRfdW1hcF9kZiRjdF9taWQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJMU0VDIiwgIkxTRUMiLCJCIGNlbGxzIiwgIlQgY2VsbHMiLCAiVCBjZWxscyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJIZXBhdG9jeXRlcyIsIkhlcGF0b2N5dGVzIiwiSGVwYXRvY3l0ZXMiKSkpCnJvd25hbWVzKG1hdGNoX2RmKSA9IG1hdGNoX2RmJGN0CgojIGNvcnJlY3Qgc29tZSBuYW1lcwpyZWZvcm1fbGlzdF9pbnQgPSBsaXN0KCkKZm9yKG4gaW4gbmFtZXMocmVmb3JtX2xpc3QpWzE6M10pewogIHJlZm9ybV9saXN0W1tuXV0kY3QxW2dyZXBsKCJIZXBhIiwgcmVmb3JtX2xpc3RbW25dXSRjdDEpXSA9ICJIZXBhdG9jeXRlcyIKICByZWZvcm1fbGlzdFtbbl1dJGN0MltncmVwbCgiSGVwYSIsIHJlZm9ybV9saXN0W1tuXV0kY3QyKV0gPSAiSGVwYXRvY3l0ZXMiCiAgcmVmb3JtX2xpc3RbW25dXSRjdDFbZ3JlcGwoIkxTRUNfIiwgcmVmb3JtX2xpc3RbW25dXSRjdDEpXSA9ICJMU0VDIgogIHJlZm9ybV9saXN0W1tuXV0kY3QyW2dyZXBsKCJMU0VDXyIsIHJlZm9ybV9saXN0W1tuXV0kY3QyKV0gPSAiTFNFQyIKICByZWZvcm1fbGlzdF9pbnRbW25dXSA9IHJlZm9ybV9saXN0W1tuXV1bcmVmb3JtX2xpc3RbW25dXSRjdDEhPSJEaXZpZGluZyBjZWxscyIgJgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlZm9ybV9saXN0W1tuXV0kY3QyIT0iRGl2aWRpbmcgY2VsbHMiLF0KICByZWZvcm1fbGlzdF9pbnRbW25dXSA9IHJlZm9ybV9saXN0X2ludFtbbl1dWyFkdXBsaWNhdGVkKHJlZm9ybV9saXN0X2ludFtbbl1dWywxOjNdKSwxOjNdCiAgCiAgcmVmb3JtX2xpc3RfaW50W1tuXV0kbWlkX2N0MSA9IG1hdGNoX2RmW3JlZm9ybV9saXN0X2ludFtbbl1dJGN0MSwiY3RfbWlkIl0KICByZWZvcm1fbGlzdF9pbnRbW25dXSRtaWRfY3QyID0gbWF0Y2hfZGZbcmVmb3JtX2xpc3RfaW50W1tuXV0kY3QyLCJjdF9taWQiXQogIAogIHJlZm9ybV9saXN0X2ludFtbbl1dID0gdW5pcXVlKHJlZm9ybV9saXN0X2ludFtbbl1dWyxjKDEsNDo1KV0pCiAgY29sbmFtZXMocmVmb3JtX2xpc3RfaW50W1tuXV0pWzI6M10gPSBjKCJjdDEiLCAiY3QyIikKfQoKIyBjb3VudCBpbnRlcmFjdGlvbnMKaW5mZXJfZGYgPSBkYXRhLmZyYW1lKGV4cGFuZC5ncmlkKHVuaXF1ZShyZWZvcm1fbGlzdF9pbnQkaGVhbHRoeSRjdDEpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHVuaXF1ZShyZWZvcm1fbGlzdF9pbnQkaGVhbHRoeSRjdDEpKSkKbnIgPSBucm93KGluZmVyX2RmKQppbmZlcl9kZiA9IHJiaW5kKGluZmVyX2RmLCBpbmZlcl9kZiwgaW5mZXJfZGYpCmluZmVyX2RmJGNvdW50ID0gMAppbmZlcl9kZiRjb25kID0gcmVwKG5hbWVzKHJlZm9ybV9saXN0KVsxOjNdLCBlYWNoID0gbnIpCmNvbG5hbWVzKGluZmVyX2RmKVsxOjJdID0gYygiU09VUkNFIiwgIlRBUkdFVCIpCmZvcihpIGluIDE6bnJvdyhpbmZlcl9kZikpewogIHRtcCA9IHJlZm9ybV9saXN0X2ludFtbaW5mZXJfZGZbaSw0XV1dCiAgaW5mZXJfZGZbaSwzXSA9IGRpbSh0bXBbKHRtcCRjdDE9PWluZmVyX2RmW2ksMV0gJiB0bXAkY3QyPT1pbmZlcl9kZltpLDJdKSB8CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAodG1wJGN0Mj09aW5mZXJfZGZbaSwxXSAmIHRtcCRjdDE9PWluZmVyX2RmW2ksMl0pLF0pWzFdCn0KIyMgbWFrZSBvbmUgdG8gY291bnQgb3ZlciBhbGwKaW5mZXJfYWxsID0gZGF0YS5mcmFtZShleHBhbmQuZ3JpZCh1bmlxdWUocmVmb3JtX2xpc3RfaW50JGhlYWx0aHkkY3QxKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdW5pcXVlKHJlZm9ybV9saXN0X2ludCRoZWFsdGh5JGN0MSkpKQppbmZlcl9hbGwkY291bnQgPSAwCmNvbG5hbWVzKGluZmVyX2FsbClbMToyXSA9IGMoIlNPVVJDRSIsICJUQVJHRVQiKQpyZWZvcm1fYWxsX2ludCA9IHVuaXF1ZShSZWR1Y2UocmJpbmQsIHJlZm9ybV9saXN0X2ludCkpCmZvcihpIGluIDE6bnJvdyhpbmZlcl9hbGwpKXsKICBpbmZlcl9hbGxbaSwzXSA9IGluZmVyX2FsbFtpLDNdK2RpbSh0bXBbKHJlZm9ybV9hbGxfaW50JGN0MT09aW5mZXJfYWxsW2ksMV0gJiByZWZvcm1fYWxsX2ludCRjdDI9PWluZmVyX2FsbFtpLDJdKSB8CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKHJlZm9ybV9hbGxfaW50JGN0Mj09aW5mZXJfYWxsW2ksMV0gJiByZWZvcm1fYWxsX2ludCRjdDE9PWluZmVyX2FsbFtpLDJdKSxdKVsxXQp9CgppbmZlcl9kZl9saXN0ID0gbGlzdChoZWFsdGh5ID0gaW5mZXJfZGZbaW5mZXJfZGYkY29uZD09ImhlYWx0aHkiLF0sCiAgICAgICAgICAgICAgICAgICAgIGVtYm9saXNlZCA9IGluZmVyX2RmW2luZmVyX2RmJGNvbmQ9PSJlbWJvbGlzZWQiLF0sCiAgICAgICAgICAgICAgICAgICAgIHJlZ2VuZXJhdGluZyA9IGluZmVyX2RmW2luZmVyX2RmJGNvbmQ9PSJyZWdlbmVyYXRpbmciLF0sCiAgICAgICAgICAgICAgICAgICAgIGFsbCA9IGluZmVyX2FsbCkKCm5ldF9uYW1lc19hbGwgPSB0KFJlZHVjZShyYmluZCwgbGFwcGx5KGluZmVyX2RmX2xpc3RbMTozXSwgZnVuY3Rpb24oeCkgdGFwcGx5KHgkY291bnQsIHgkU09VUkNFLCBzdW0pKSkpCmNvbG5hbWVzKG5ldF9uYW1lc19hbGwpID0gbmFtZXMobmV0X25hbWVzX2wpWzE6M10KbmV0X25hbWVzX2FsbCA9IHJlc2hhcGUyOjptZWx0KG5ldF9uYW1lc19hbGwpCm5ldF9uYW1lc19hbGwkVmFyMSA9IGZhY3RvcihuZXRfbmFtZXNfYWxsJFZhcjEsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgbGV2ZWxzID0gbmV0X25hbWVzX2FsbFtuZXRfbmFtZXNfYWxsJFZhcjI9PSJoZWFsdGh5IiwiVmFyMSJdW29yZGVyKG5ldF9uYW1lc19hbGxbbmV0X25hbWVzX2FsbCRWYXIyPT0iaGVhbHRoeSIsInZhbHVlIl0sIGRlY3JlYXNpbmcgPSBGKV0pCgp0b3RhbF91bmlxdWUgPSBkYXRhLmZyYW1lKHQodChSZWR1Y2UocmJpbmQsIGxhcHBseShpbmZlcl9kZl9saXN0WzRdLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZnVuY3Rpb24oeCkgdGFwcGx5KHgkY291bnQsIHgkU09VUkNFLCBzdW0pKSkpKSkKdG90YWxfdW5pcXVlJFZhcjEgPSByb3duYW1lcyh0b3RhbF91bmlxdWUpCmNvbG5hbWVzKHRvdGFsX3VuaXF1ZSlbMV0gPSAidmFsdWUiCnRvdGFsX3VuaXF1ZSRWYXIyID0gInRvdGFsIHVuaXF1ZSIKCm5ldF9uYW1lc19hbGwkVmFyMSA9IGZhY3RvcihuZXRfbmFtZXNfYWxsJFZhcjEsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgbGV2ZWxzID0gdG90YWxfdW5pcXVlJFZhcjFbb3JkZXIodG90YWxfdW5pcXVlJHZhbHVlLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRlY3JlYXNpbmcgPSBGKV0pCnBsdF9jb3VudHMgPSBnZ3Bsb3QobmV0X25hbWVzX2FsbCwgYWVzKHggPSBWYXIxLCB5ID0gdmFsdWUpKSsKICBnZW9tX3BvaW50KG1hcHBpbmcgPSBhZXMoY29sb3VyID0gVmFyMiksIHNpemUgPSAxLjYpKwogIGdlb21fcG9pbnQoZGF0YSA9IHRvdGFsX3VuaXF1ZSwgbWFwcGluZyA9IGFlcyhzaGFwZSA9IFZhcjIpLCBzaXplID0gMS42KSsKICBjb29yZF9mbGlwKCkrCiAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBjb2xjb25kWzE6M10pKwogIHNjYWxlX3NoYXBlX21hbnVhbCh2YWx1ZXMgPSBjKDQpKSsKICBzY2FsZV95X2NvbnRpbnVvdXMoZXhwYW5kID0gYygwLDApLCBsaW1pdHMgPSBjKDAsMzAwMCkpKwogIGxhYnMoeSA9ICJUb3RhbCBpbnRlcmFjdGlvbnMiLCB4ID0gIkNlbGwgVHlwZSIsIGNvbG91ciA9ICJDb25kaXRpb24iKSsKICBndWlkZXMoY29sb3VyID0gZ3VpZGVfbGVnZW5kKG9yZGVyID0gMSksIHNoYXBlID0gZ3VpZGVfbGVnZW5kKG9yZGVyID0gMiwgdGl0bGUgPSBOVUxMKSkrCiAgdGhlbWVfYncoKSsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDMwLCB2anVzdCA9IDEsIGhqdXN0ID0gMSksCiAgICAgICAgYXhpcy50ZXh0ID0gZWxlbWVudF90ZXh0KGNvbG91ciA9ICJibGFjayIpLAogICAgICAgIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfdGV4dChzaXplID0gOCksCiAgICAgICAgbGVnZW5kLm1hcmdpbiA9IG1hcmdpbigxLCAxLCAxLCAxKSwKICAgICAgICBsZWdlbmQuc3BhY2luZy54ID0gdW5pdCgwLjA1LCAiY20iKSwKICAgICAgICBsZWdlbmQuZGlyZWN0aW9uID0gImhvcml6b250YWwiLGxlZ2VuZC5ib3ggPSAiaG9yaXpvbnRhbCIpCmxlZyA9IGNvd3Bsb3Q6OmdldF9sZWdlbmQocGx0X2NvdW50cykKCnBlcmNfZGYgPSBkYXRhLmZyYW1lKCJWYXIxIiA9IG5ldF9uYW1lc19hbGwkVmFyMSwKICAgICAgICAgICAgICAgICAgICAgIlZhcjIiID0gbmV0X25hbWVzX2FsbCRWYXIyLAogICAgICAgICAgICAgICAgICAgICAicGVyYyIgPSBjKHJlcCgwLCBsZW5ndGgodW5pcXVlKG5ldF9uYW1lc19hbGwkVmFyMSkpKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAobmV0X25hbWVzX2FsbCR2YWx1ZVtuZXRfbmFtZXNfYWxsJFZhcjI9PSJlbWJvbGlzZWQiXS1uZXRfbmFtZXNfYWxsJHZhbHVlW25ldF9uYW1lc19hbGwkVmFyMj09ImhlYWx0aHkiXSkvbmV0X25hbWVzX2FsbCR2YWx1ZVtuZXRfbmFtZXNfYWxsJFZhcjI9PSJoZWFsdGh5Il0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKG5ldF9uYW1lc19hbGwkdmFsdWVbbmV0X25hbWVzX2FsbCRWYXIyPT0icmVnZW5lcmF0aW5nIl0tbmV0X25hbWVzX2FsbCR2YWx1ZVtuZXRfbmFtZXNfYWxsJFZhcjI9PSJoZWFsdGh5Il0pL25ldF9uYW1lc19hbGwkdmFsdWVbbmV0X25hbWVzX2FsbCRWYXIyPT0iaGVhbHRoeSJdKSoxMDApCnBlcmNfZGYkY29sID0gaWZlbHNlKHBlcmNfZGYkcGVyYz4wLCAiZ3JlZW4iLCAicmVkIikKcGVyY19kZiA9IHBlcmNfZGZbcGVyY19kZiRWYXIyIT0iaGVhbHRoeSIsXQoKcGVyY19wbHRfZW1iID0gZ2dwbG90KHBlcmNfZGZbcGVyY19kZiRWYXIyPT0iZW1ib2xpc2VkIixdLCBhZXMoeCA9IFZhcjEsIHkgPSBwZXJjLCBmaWxsID0gY29sKSkrCiAgZ2VvbV9jb2woKSsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCJkZWVwc2t5Ymx1ZTEiLCAicmVkMSIpKSsKICBzY2FsZV95X2NvbnRpbnVvdXMoZXhwYW5kID0gYygwLDApLCBsaW1pdHMgPSBjKC0yMCw1NSkpKwogIGNvb3JkX2ZsaXAoKSsKICBsYWJzKHkgPSAiJSBjaGFuZ2VcbmVtYm9saXNlZCB2cyBoZWFsdGh5IiwgeCA9ICJDZWxsIFR5cGUiKSsKICB0aGVtZV9idygpKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gMzAsIHZqdXN0ID0gMSwgaGp1c3QgPSAxLCBjb2xvdXIgPSAiYmxhY2siKSwKICAgICAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRpdGxlLnggPSBlbGVtZW50X3RleHQoc2l6ZSA9IDgpLAogICAgICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRpY2tzLnkgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQpwZXJjX3BsdF9yZWcgPSBnZ3Bsb3QocGVyY19kZltwZXJjX2RmJFZhcjI9PSJyZWdlbmVyYXRpbmciLF0sIGFlcyh4ID0gVmFyMSwgeSA9IHBlcmMsIGZpbGwgPSBjb2wpKSsKICBnZW9tX2NvbCgpKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoImRlZXBza3libHVlMSIsICJyZWQxIikpKwogIHNjYWxlX3lfY29udGludW91cyhleHBhbmQgPSBjKDAsMCksIGxpbWl0cyA9IGMoLTIwLDU1KSkrCiAgY29vcmRfZmxpcCgpKwogIGxhYnMoeSA9ICIlIGNoYW5nZVxucmVnZW5lcmF0aW5nIHZzIGhlYWx0aHkiLCB4ID0gIkNlbGwgVHlwZSIpKwogIHRoZW1lX2J3KCkrCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSAzMCwgdmp1c3QgPSAxLCBoanVzdCA9IDEsIGNvbG91ciA9ICJibGFjayIpLAogICAgICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfdGV4dChzaXplID0gOCksCiAgICAgICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGlja3MueSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpCgpjb3dwbG90OjpwbG90X2dyaWQoY293cGxvdDo6cGxvdF9ncmlkKHBsdF9jb3VudHMrdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGVyY19wbHRfZW1iLCBwZXJjX3BsdF9yZWcsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5jb2wgPSAzLCBhbGlnbiA9ICJoIiwgYXhpcyA9ICJyIiwgcmVsX3dpZHRocyA9IGMoMSwwLjUsMC41KSksCiAgICAgICAgICAgICAgICAgICBsZWcsIG5yb3cgPSAyLCByZWxfaGVpZ2h0cyA9IGMoMSwgMC4xKSkKCnBkZigiZmlndXJlX3BhbmVsc19yZXYxL2ZpZ19jb21tL21haW5GaWdfY291bnRzQ29uZF9taWQucGRmIiwgaGVpZ2h0ID0gMy4zNSwgd2lkdGggPSA1LjUpCmNvd3Bsb3Q6OnBsb3RfZ3JpZChjb3dwbG90OjpwbG90X2dyaWQocGx0X2NvdW50cyt0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwZXJjX3BsdF9yZWcsIHBlcmNfcGx0X2VtYiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbmNvbCA9IDMsIGFsaWduID0gImgiLCBheGlzID0gInIiLCByZWxfd2lkdGhzID0gYygxLDAuNCwwLjQpKSwKICAgICAgICAgICAgICAgICAgIGxlZywgbnJvdyA9IDIsIHJlbF9oZWlnaHRzID0gYygxLCAwLjEpKQpkZXYub2ZmKCkKYGBgCgoKCgojIFBhbmVscyBjaXJyaG9zaXMKVU1BUCBJbW11bmUgY2VsbHMKCmBgYHtyLCBmaWcuaGVpZ2h0PTIsIGZpZy53aWR0aD0yLjc1fQppbW1fZGYgPSByZWFkUkRTKCJyZXN1bHRzL2NpcnJob3Npcy91bWFwX2ltbV9kZi5SRFMiKQoKY29scyA9IE1ldEJyZXdlcjo6bWV0LmJyZXdlcigiRWd5cHQiLCBsZW5ndGgodW5pcXVlKGltbV9kZiRzaW1wX2Fubm90KSkpCm5hbWVzKGNvbHMpID0gdW5pcXVlKGltbV9kZiRzaW1wX2Fubm90KQpjb2xzWyJOb24gYW5ub3RhdGVkIGNlbGxzIl0gPSAiZ3JleTgwIgoKaW1tX2RmID0gaW1tX2RmW3NhbXBsZSgxOm5yb3coaW1tX2RmKSwgbnJvdyhpbW1fZGYpLCByZXBsYWNlID0gRiksXQpwbHQgPSBnZ3Bsb3QoKSsKICBnZW9tX3BvaW50KGFlcyh4ID0gVU1BUF8xLCB5ID0gVU1BUF8yLCBjb2xvdXIgPSBzaW1wX2Fubm90KSwgCiAgICAgICAgICAgICBpbW1fZGYsIHNpemUgPSAwLjIpKwogIGd1aWRlcyhjb2xvdXIgPSBndWlkZV9sZWdlbmQob3ZlcnJpZGUuYWVzID0gbGlzdChzaXplID0gMykpKSsKICBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcyA9IGNvbHNbb3JkZXIobmFtZXMoY29scykpXSkrCiAgdGhlbWVfdm9pZCgpKwogIHRoZW1lKGFzcGVjdC5yYXRpbyA9IDEsCiAgICAgICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDcpLAogICAgICAgIGxlZ2VuZC5rZXkuc2l6ZSA9IHVuaXQoMC40LCAiY20iKSwKICAgICAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpCgpwZGYoImZpZ3VyZV9wYW5lbHNfcmV2MS9maWdfY2lyL2FsbF9pbW11bmVfdW1hcC5wZGYiLCBoZWlnaHQgPSAyLjIsIHdpZHRoID0gNC4yKQpwcmludChwbHQpCmRldi5vZmYoKQpgYGAKClVNQVAgTW9uby9NYWMgY2VsbHMKCmBgYHtyLCBmaWcuaGVpZ2h0PTIsIGZpZy53aWR0aD0yLjc1fQptX2RmID0gcmVhZFJEUyhmaWxlID0gInJlc3VsdHMvY2lycmhvc2lzL3VtYXBfbV9kZi5SRFMiKQoKY29scyA9IE1ldEJyZXdlcjo6bWV0LmJyZXdlcigiS2xpbXQiLCBsZW5ndGgodW5pcXVlKG1fZGYkYWxsX2Fubm90KSkpCm5hbWVzKGNvbHMpID0gdW5pcXVlKG1fZGYkYWxsX2Fubm90KQoKbV9kZiA9IG1fZGZbc2FtcGxlKDE6bnJvdyhtX2RmKSwgbnJvdyhtX2RmKSwgcmVwbGFjZSA9IEYpLF0KcGx0ID0gZ2dwbG90KCkrCiAgZ2VvbV9wb2ludChhZXMoeCA9IFVNQVBfMSwgeSA9IFVNQVBfMiwgY29sb3VyID0gYWxsX2Fubm90KSwgCiAgICAgICAgICAgICBtX2RmLCBzaXplID0gMC4yKSsKICBndWlkZXMoY29sb3VyID0gZ3VpZGVfbGVnZW5kKG92ZXJyaWRlLmFlcyA9IGxpc3Qoc2l6ZSA9IDMpKSkrCiAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBjb2xzW29yZGVyKG5hbWVzKGNvbHMpKV0pKwogIHRoZW1lX3ZvaWQoKSsKICB0aGVtZShhc3BlY3QucmF0aW8gPSAxLAogICAgICAgIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSA2KSwKICAgICAgICBsZWdlbmQua2V5LnNpemUgPSB1bml0KDAuNCwgImNtIiksCiAgICAgICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF9ibGFuaygpKQoKcGRmKCJmaWd1cmVfcGFuZWxzX3JldjEvZmlnX2Npci9hbGxfbW9ub191bWFwLnBkZiIsIGhlaWdodCA9IDIuMiwgd2lkdGggPSA0LjIpCnByaW50KHBsdCkKZGV2Lm9mZigpCmBgYAoKVU1BUCBUL05LIGNlbGxzCgpgYGB7cn0KdF9kZiA9IHJlYWRSRFMoZmlsZSA9ICJyZXN1bHRzL2NpcnJob3Npcy91bWFwX3RfZGYuUkRTIikKCmNvbHMgPSBNZXRCcmV3ZXI6Om1ldC5icmV3ZXIoIkp1YXJleiIsIGxlbmd0aCh1bmlxdWUodF9kZiRhbGxfYW5ub3QpKSkKbmFtZXMoY29scykgPSB1bmlxdWUodF9kZiRhbGxfYW5ub3QpCgp0X2RmID0gdF9kZltzYW1wbGUoMTpucm93KHRfZGYpLCBucm93KHRfZGYpLCByZXBsYWNlID0gRiksXQpwbHQgPSBnZ3Bsb3QoKSsKICBnZW9tX3BvaW50KGFlcyh4ID0gVU1BUF8xLCB5ID0gVU1BUF8yLCBjb2xvdXIgPSBhbGxfYW5ub3QpLCAKICAgICAgICAgICAgIHRfZGYsIHNpemUgPSAwLjIpKwogIGd1aWRlcyhjb2xvdXIgPSBndWlkZV9sZWdlbmQob3ZlcnJpZGUuYWVzID0gbGlzdChzaXplID0gMykpKSsKICBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcyA9IGNvbHNbb3JkZXIobmFtZXMoY29scykpXSkrCiAgdGhlbWVfdm9pZCgpKwogIHRoZW1lKGFzcGVjdC5yYXRpbyA9IDEsCiAgICAgICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDYpLAogICAgICAgIGxlZ2VuZC5rZXkuc2l6ZSA9IHVuaXQoMC4zNzUsICJjbSIpLAogICAgICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkKCnBkZigiZmlndXJlX3BhbmVsc19yZXYxL2ZpZ19jaXIvYWxsX3Rua191bWFwLnBkZiIsIGhlaWdodCA9IDIuMiwgd2lkdGggPSA0LjIpCnByaW50KHBsdCkKZGV2Lm9mZigpCmBgYAoKTWFya2VycyBteWVsb2lkIGNlbGxzCgpgYGB7cn0KbWF0X20gPSByZWFkUkRTKGZpbGUgPSAicmVzdWx0cy9jaXJyaG9zaXMvbWF0X215ZWxvaWRfbWFya2Vycy5SRFMiKQoKY29sc19wYWwgPSBjb2xvclJhbXBQYWxldHRlKHJldihicmV3ZXIucGFsKG4gPSA5LCBuYW1lID0gIlJkQnUiKSkpKDEwMCkKCnBkZigiZmlndXJlX3BhbmVsc19yZXYxL2ZpZ19jaXIvaGVhdF9ta19teWUucGRmIiwgaGVpZ2h0ID0gMi4yLCB3aWR0aCA9IDYuMykKcGhlYXRtYXA6OnBoZWF0bWFwKG1hdF9tLCBjbHVzdGVyaW5nX21ldGhvZCA9ICJ3YXJkLkQiLCBjb2xvciA9IGNvbHNfcGFsLAogICAgICAgICAgICAgICAgICAgdHJlZWhlaWdodF9jb2wgPSAwLCB0cmVlaGVpZ2h0X3JvdyA9IDIwLCBmb250c2l6ZSA9IDYuMykKZGV2Lm9mZigpCmBgYAoKTWFya2VycyBseW1waG9pZCBjZWxscwoKYGBge3J9Cm1hdF9sID0gcmVhZFJEUygicmVzdWx0cy9jaXJyaG9zaXMvbWF0X2x5bXBob2lkX21hcmtlcnMuUkRTIikKCmNvbHNfcGFsID0gY29sb3JSYW1wUGFsZXR0ZShyZXYoYnJld2VyLnBhbChuID0gOSwgbmFtZSA9ICJSZEJ1IikpKSgxMDApCgpwZGYoImZpZ3VyZV9wYW5lbHNfcmV2MS9maWdfY2lyL2hlYXRfbWtfbHltLnBkZiIsIGhlaWdodCA9IDIuMiwgd2lkdGggPSA2LjMpCnBoZWF0bWFwOjpwaGVhdG1hcChtYXRfbCwgY2x1c3RlcmluZ19tZXRob2QgPSAid2FyZC5EIiwgY29sb3IgPSBjb2xzX3BhbCwKICAgICAgICAgICAgICAgICAgIHRyZWVoZWlnaHRfY29sID0gMCwgdHJlZWhlaWdodF9yb3cgPSAyMCwgZm9udHNpemUgPSA2LjMpCmRldi5vZmYoKQpgYGAKClByb3BvcnRpb25zIGltbXVuZSBjZWxscwoKYGBge3J9CmltbV9wcm9wcyA9IHJlYWRSRFMoZmlsZSA9ICJyZXN1bHRzL2NpcnJob3Npcy9pbW1fcHJvcHNfZGF0LlJEUyIpCmltbV9wdmFscyA9IHJlYWRSRFMoInJlc3VsdHMvY2lycmhvc2lzL2ltbV9wcm9wc19wdmFsLlJEUyIpCgpwbHQgPSBnZ3Bsb3QoaW1tX3Byb3BzLCBhZXMoeCA9IENvbmRpdGlvbiwgeSA9IEZyZXEsIGdyb3VwID0gQ29uZGl0aW9uLCBjb2xvdXIgPSBDb25kaXRpb24pKSsKICBmYWNldF93cmFwKH5WYXIxLCBzY2FsZXMgPSAiZnJlZSIpKwogIGdlb21faml0dGVyKHBvc2l0aW9uID0gcG9zaXRpb25faml0dGVyZG9kZ2Uoaml0dGVyLndpZHRoID0gMC4zLCBkb2RnZS53aWR0aCA9IDEpKSsKICBzdGF0X3N1bW1hcnkoZnVuLmRhdGEgPSBtZWFuX3NlLCBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMSksIAogICAgICAgICAgICAgICBhbHBoYSA9IDAuMzUsIGNvbG91ciA9ICJibGFjayIpKwogIHRoZW1lX2J3KCkrCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQoKCmNvbG5hbWVzKGltbV9wdmFscylbMV0gPSAiZW1ib2xpemVkIgoKaW1tX3Byb3BzJENvbmRpdGlvbltpbW1fcHJvcHMkQ29uZGl0aW9uPT0iZW1ib2xpc2VkIl0gPSAiZW1ib2xpemVkIgppbW1fcHJvcHMkQ29uZGl0aW9uID0gZmFjdG9yKGltbV9wcm9wcyRDb25kaXRpb24sIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxldmVscyA9IGMoImhlYWx0aHkiLCAicmVnZW5lcmF0aW5nIiwgImVtYm9saXplZCIpKQoKcHZhbF9wb3MgPSBpbW1fcHJvcHMgJT4lCiAgZ3JvdXBfYnkoQ29uZGl0aW9uLCBWYXIxKSAlPiUKICBzdW1tYXJpc2VfYXQodmFycygiRnJlcSIpLCBtZWFuKQpwdmFsX3BvcyRwb3N5ID0gcHZhbF9wb3MkRnJlcSoxLjAyCnB2YWxfcG9zJHBvc3ggPSBhcy5udW1lcmljKHB2YWxfcG9zJENvbmRpdGlvbikrMC4zCnB2YWxfcG9zID0gcHZhbF9wb3NbcHZhbF9wb3MkQ29uZGl0aW9uIT0iaGVhbHRoeSIsXQpwdmFsX3BvcyRwdmFsID0gZGlhZyhhcy5tYXRyaXgoaW1tX3B2YWxzW3B2YWxfcG9zJFZhcjEsYXMuY2hhcmFjdGVyKHB2YWxfcG9zJENvbmRpdGlvbildKSkKcHZhbF9wb3MkaXNzaWcgPSBpZmVsc2UocHZhbF9wb3MkcHZhbDw9MC4wNSwgIioiLCAiIikKCnBsdCA9IGdncGxvdCgpKwogIGZhY2V0X3dyYXAoflZhcjEsIHNjYWxlcyA9ICJmcmVlIikrCiAgZ2VvbV9qaXR0ZXIoZGF0YSA9IGltbV9wcm9wcywgbWFwcGluZyA9IGFlcyh4ID0gQ29uZGl0aW9uLCB5ID0gRnJlcSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBncm91cCA9IENvbmRpdGlvbiwgY29sb3VyID0gQ29uZGl0aW9uKSwKICAgICAgICAgICAgICBwb3NpdGlvbiA9IHBvc2l0aW9uX2ppdHRlcmRvZGdlKGppdHRlci53aWR0aCA9IDAuMywgZG9kZ2Uud2lkdGggPSAxKSwgc2l6ZSA9IDAuNSkrCiAgc3RhdF9zdW1tYXJ5KGRhdGEgPSBpbW1fcHJvcHMsIG1hcHBpbmcgPSBhZXMoeCA9IENvbmRpdGlvbiwgeSA9IEZyZXEsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ3JvdXAgPSBDb25kaXRpb24sIGNvbG91ciA9IENvbmRpdGlvbiksCiAgICAgICAgICAgICAgIGZ1bi5kYXRhID0gbWVhbl9zZSwgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDEpLCAKICAgICAgICAgICAgICAgYWxwaGEgPSAwLjYsIGNvbG91ciA9ICJibGFjayIsIHNpemUgPSAwLjI1KSsKICBnZW9tX3RleHQoZGF0YSA9IHB2YWxfcG9zLCBtYXBwaW5nID0gYWVzKHggPSBwb3N4LCB5ID0gcG9zeSwgbGFiZWwgPSBpc3NpZyksIHNpemUgPSA0KSsKICBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcyA9IGNvbGNvbmQsIGRyb3AgPSBULCBsaW1pdHMgPSBuYW1lcyhjb2xjb25kKVtjKDEsMiw0KV0pKwogIHNjYWxlX3hfZGlzY3JldGUobGFiZWxzID0gYygiSCIsICJSIiwgIkUiKSkrCiAgbGFicyh5ID0gInByb3BvcnRpb24gJSAoaW1tdW5lKSIpKwogIHRoZW1lX2J3KCkrCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLAogICAgICAgIGF4aXMudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDYsIGNvbG91ciA9ICJibGFjayIpLAogICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KHNpemUgPSA2LCBjb2xvdXIgPSAiYmxhY2siKSwKICAgICAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplID0gNiwgY29sb3VyID0gImJsYWNrIiksCiAgICAgICAgc3RyaXAudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gNiksCiAgICAgICAgc3RyaXAuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gIndoaXRlIiksCiAgICAgICAgcGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBwYW5lbC5ncmlkLm1ham9yLnggPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgcGFuZWwuZ3JpZC5tYWpvci55ID0gZWxlbWVudF9saW5lKHNpemUgPSAwLjMsIGNvbG91ciA9ICJncmV5NzAiKSkKCiNwZGYoImZpZ3VyZV9wYW5lbHNfcmV2MS9maWdfY2lyL2ltbXVuZV9hbGxfcHJvcC5wZGYiLCBoZWlnaHQgPSA3LjUsIHdpZHRoID0gMTEuNSkKcHJpbnQocGx0KQojZGV2Lm9mZigpCgpwZGYoImZpZ3VyZV9wYW5lbHNfcmV2MS9maWdfY2lyL2ltbXVuZV9hbGxfcHJvcF9yZXNpemVkLnBkZiIsIGhlaWdodCA9IDUuNSwgd2lkdGggPSA3KQpwcmludChwbHQpCmRldi5vZmYoKQpgYGAKClByb3BvcnRpb25zIGVuZG90aGVsaWFsIGNlbGxzCgpgYGB7cn0KZW5kX3Byb3BzID0gcmVhZFJEUyhmaWxlID0gInJlc3VsdHMvY2lycmhvc2lzL2VuZF9wcm9wc19kYXQuUkRTIikKZW5kX3B2YWxzID0gcmVhZFJEUygicmVzdWx0cy9jaXJyaG9zaXMvZW5kX3Byb3BzX3B2YWwuUkRTIikKY29sbmFtZXMoZW5kX3B2YWxzKVsxXSA9ICJlbWJvbGl6ZWQiCgplbmRfcHJvcHMkQ29uZGl0aW9uW2VuZF9wcm9wcyRDb25kaXRpb249PSJlbWJvbGlzZWQiXSA9ICJlbWJvbGl6ZWQiCmVuZF9wcm9wcyRDb25kaXRpb24gPSBmYWN0b3IoZW5kX3Byb3BzJENvbmRpdGlvbiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGV2ZWxzID0gYygiaGVhbHRoeSIsICJyZWdlbmVyYXRpbmciLCAiZW1ib2xpemVkIikpCgpwdmFsX3BvcyA9IGVuZF9wcm9wcyAlPiUKICBncm91cF9ieShDb25kaXRpb24sIFZhcjEpICU+JQogIHN1bW1hcmlzZV9hdCh2YXJzKCJGcmVxIiksIG1lYW4pCnB2YWxfcG9zJHBvc3kgPSBwdmFsX3BvcyRGcmVxKjEuMDIKcHZhbF9wb3MkcG9zeCA9IGFzLm51bWVyaWMocHZhbF9wb3MkQ29uZGl0aW9uKSswLjIKcHZhbF9wb3MgPSBwdmFsX3Bvc1twdmFsX3BvcyRDb25kaXRpb24hPSJoZWFsdGh5IixdCnB2YWxfcG9zJHB2YWwgPSBkaWFnKGFzLm1hdHJpeChlbmRfcHZhbHNbcHZhbF9wb3MkVmFyMSxhcy5jaGFyYWN0ZXIocHZhbF9wb3MkQ29uZGl0aW9uKV0pKQpwdmFsX3BvcyRpc3NpZyA9IGlmZWxzZShwdmFsX3BvcyRwdmFsPD0wLjA1LCAiKiIsICIiKQoKcGx0ID0gZ2dwbG90KCkrCiAgZmFjZXRfd3JhcCh+VmFyMSwgc2NhbGVzID0gImZyZWUiKSsKICBnZW9tX2ppdHRlcihkYXRhID0gZW5kX3Byb3BzLCBtYXBwaW5nID0gYWVzKHggPSBDb25kaXRpb24sIHkgPSBGcmVxLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdyb3VwID0gQ29uZGl0aW9uLCBjb2xvdXIgPSBDb25kaXRpb24pLAogICAgICAgICAgICAgIHBvc2l0aW9uID0gcG9zaXRpb25faml0dGVyZG9kZ2Uoaml0dGVyLndpZHRoID0gMC4zLCBkb2RnZS53aWR0aCA9IDEpKSsKICBzdGF0X3N1bW1hcnkoZGF0YSA9IGVuZF9wcm9wcywgbWFwcGluZyA9IGFlcyh4ID0gQ29uZGl0aW9uLCB5ID0gRnJlcSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBncm91cCA9IENvbmRpdGlvbiwgY29sb3VyID0gQ29uZGl0aW9uKSwKICAgICAgICAgICAgICAgZnVuLmRhdGEgPSBtZWFuX3NlLCBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMSksIAogICAgICAgICAgICAgICBhbHBoYSA9IDAuNiwgY29sb3VyID0gImJsYWNrIikrCiAgZ2VvbV90ZXh0KGRhdGEgPSBwdmFsX3BvcywgbWFwcGluZyA9IGFlcyh4ID0gcG9zeCwgeSA9IHBvc3ksIGxhYmVsID0gaXNzaWcpLCBzaXplID0gNikrCiAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBjb2xjb25kLCBkcm9wID0gVCwgbGltaXRzID0gbmFtZXMoY29sY29uZClbYygxLDIsNCldKSsKICBsYWJzKHkgPSAiJSAoZW5kb3RoZWxpYWwpIikrCiAgdGhlbWVfYncoKSsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIsCiAgICAgICAgYXhpcy50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gNy41LCBjb2xvdXIgPSAiYmxhY2siKSwKICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChzaXplID0gNywgY29sb3VyID0gImJsYWNrIiksCiAgICAgICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDYsIGNvbG91ciA9ICJibGFjayIpLAogICAgICAgIHN0cmlwLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDcpLAogICAgICAgIHN0cmlwLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJ3aGl0ZSIpLAogICAgICAgIHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgcGFuZWwuZ3JpZC5tYWpvci54ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIHBhbmVsLmdyaWQubWFqb3IueSA9IGVsZW1lbnRfbGluZShzaXplID0gMC4zLCBjb2xvdXIgPSAiZ3JleTcwIikpCgpwZGYoImZpZ3VyZV9wYW5lbHNfcmV2MS9maWdfY2lyL2VuZG9fYWxsX3Byb3AucGRmIiwgaGVpZ2h0ID0gNSwgd2lkdGggPSA3LjgpCnByaW50KHBsdCkKZGV2Lm9mZigpCmBgYAoKTVAgc2lnbmF0dXJlcwoKYGBge3J9Cm1wX3NpZ19kZiA9IHJlYWRSRFMoZmlsZSA9ICJyZXN1bHRzL2NpcnJob3Npcy9tb25vX2NpcnJfY3Rfc2lnbmF0dXJlcy5SRFMiKQoKcGxvdF9kZiA9IHJlc2hhcGUyOjptZWx0KG1wX3NpZ19kZikKcGxvdF9kZiRDb25kaXRpb25bcGxvdF9kZiRDb25kaXRpb249PSJlbWJvbGlzZWQiXSA9ICJlbWJvbGl6ZWQiCnBsb3RfZGYkQ29uZGl0aW9uID0gZmFjdG9yKHBsb3RfZGYkQ29uZGl0aW9uLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgbGV2ZWxzID0gYygiaGVhbHRoeSIsInJlZ2VuZXJhdGluZyIsImVtYm9saXplZCIpKQpzdWJfcGxvdF9kZiA9IHBsb3RfZGZbcGxvdF9kZiR2YXJpYWJsZSAlaW4lIGMoImNpcnJfY3RfTVBzXzQiLCJjaXJyX2N0X01Qc181IiksXQpzdWJfcGxvdF9kZiR2YXJpYWJsZSA9IGdzdWIoImNpcnJfY3RfTVBzXzQiLCAiU0FNYWMgKDEpIiwgc3ViX3Bsb3RfZGYkdmFyaWFibGUpCnN1Yl9wbG90X2RmJHZhcmlhYmxlID0gZ3N1YigiY2lycl9jdF9NUHNfNSIsICJTQU1hYyAoMikiLCBzdWJfcGxvdF9kZiR2YXJpYWJsZSkKCnBsdCA9IGdncGxvdChzdWJfcGxvdF9kZiwgYWVzKHggPSBtb25vX2Fubm90LCB5ID0gdmFsdWUsIGZpbGwgPSBDb25kaXRpb24pKSsKICBmYWNldF9ncmlkKHZhcmlhYmxlfm1vbm9fYW5ub3QsIHNjYWxlcyA9ICJmcmVlIikrCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCwgbGluZXR5cGUgPSAiZGFzaGVkIiwgc2l6ZSA9IDAuMykrCiAgZ2VvbV92aW9saW4oc2NhbGUgPSAiY291bnQiKSsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjb2xjb25kLCBkcm9wID0gVCwgbGltaXRzID0gbmFtZXMoY29sY29uZClbYygxLDIsNCldKSsKICB0aGVtZV9jbGFzc2ljKCkrCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGlja3MueCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplID0gNiwgY29sb3VyID0gImJsYWNrIiksCiAgICAgICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF90ZXh0KHNpemUgPSA2LjUpLAogICAgICAgIHN0cmlwLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDcpLAogICAgICAgIHBhbmVsLmJvcmRlciA9IGVsZW1lbnRfcmVjdChjb2xvdXIgPSAiYmxhY2siLCBmaWxsID0gTkEpLAogICAgICAgIGF4aXMubGluZSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBsZWdlbmQucG9zaXRpb24gPSBjKDAuMDQ4LCAwLjg2NSksCiAgICAgICAgbGVnZW5kLmJhY2tncm91bmQgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgbGVnZW5kLmtleS5zaXplID0gdW5pdCgwLjMsICJjbSIpLAogICAgICAgIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSA2LjUpLAogICAgICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gNykpCgpwZGYoImZpZ3VyZV9wYW5lbHNfcmV2MS9maWdfY2lyL21wX3NpZ192aW8ucGRmIiwgaGVpZ2h0ID0gMywgd2lkdGggPSAxMC4zNSkKcHJpbnQocGx0KQpkZXYub2ZmKCkKYGBgCgpFbmRvdGhlbGlhbCBzaWduYXR1cmVzCgpgYGB7cn0KZW5kX3NpZ19kZiA9IHJlYWRSRFMoZmlsZSA9ICJyZXN1bHRzL2NpcnJob3Npcy9lbmRvX2NpcnJfY3Rfc2lnbmF0dXJlcy5SRFMiKQoKcGxvdF9kZiA9IHJlc2hhcGUyOjptZWx0KGVuZF9zaWdfZGYpCnBsb3RfZGYkQ29uZGl0aW9uW3Bsb3RfZGYkQ29uZGl0aW9uPT0iZW1ib2xpc2VkIl0gPSAiZW1ib2xpemVkIgpwbG90X2RmJENvbmRpdGlvbltwbG90X2RmJENvbmRpdGlvbj09ImVtYm9saXNlZCJdID0gImVtYm9saXplZCIKcGxvdF9kZiRDb25kaXRpb24gPSBmYWN0b3IocGxvdF9kZiRDb25kaXRpb24sIAogICAgICAgICAgICAgICAgICAgICAgICAgICBsZXZlbHMgPSBjKCJoZWFsdGh5IiwicmVnZW5lcmF0aW5nIiwiZW1ib2xpemVkIikpCnN1Yl9wbG90X2RmID0gcGxvdF9kZltwbG90X2RmJHZhcmlhYmxlICVpbiUgYygiY2lycl9jdF9FbmRvdGhlbGlhXzYiLCJjaXJyX2N0X0VuZG90aGVsaWFfNyIpLF0Kc3ViX3Bsb3RfZGYkdmFyaWFibGUgPSBnc3ViKCJjaXJyX2N0X0VuZG90aGVsaWFfNiIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIlNBRW5kb3RoZWxpYWwgKDEpIiwgc3ViX3Bsb3RfZGYkdmFyaWFibGUpCnN1Yl9wbG90X2RmJHZhcmlhYmxlID0gZ3N1YigiY2lycl9jdF9FbmRvdGhlbGlhXzciLCAiU0FFbmRvdGhlbGlhbCAoMikiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgc3ViX3Bsb3RfZGYkdmFyaWFibGUpCgpwbHQgPSBnZ3Bsb3Qoc3ViX3Bsb3RfZGYsIGFlcyh4ID0gZW5kb19zaW1wLCB5ID0gdmFsdWUsIGZpbGwgPSBDb25kaXRpb24pKSsKICBmYWNldF9ncmlkKHZhcmlhYmxlfmVuZG9fc2ltcCwgc2NhbGVzID0gImZyZWUiKSsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwLCBsaW5ldHlwZSA9ICJkYXNoZWQiLCBzaXplID0gMC4zKSsKICBnZW9tX3Zpb2xpbihzY2FsZSA9ICJjb3VudCIpKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGNvbGNvbmQsIGRyb3AgPSBULCBsaW1pdHMgPSBuYW1lcyhjb2xjb25kKVtjKDEsMiw0KV0pKwogIHRoZW1lX2NsYXNzaWMoKSsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRpdGxlLnggPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy50aWNrcy54ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemUgPSA2LCBjb2xvdXIgPSAiYmxhY2siKSwKICAgICAgICBheGlzLnRpdGxlLnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDYuNSksCiAgICAgICAgc3RyaXAudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gNyksCiAgICAgICAgcGFuZWwuYm9yZGVyID0gZWxlbWVudF9yZWN0KGNvbG91ciA9ICJibGFjayIsIGZpbGwgPSBOQSksCiAgICAgICAgYXhpcy5saW5lID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iLAogICAgICAgIGxlZ2VuZC5iYWNrZ3JvdW5kID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGxlZ2VuZC5tYXJnaW4gPSBtYXJnaW4oMCwwLDAsMCksCiAgICAgICAgbGVnZW5kLmtleS5zaXplID0gdW5pdCgwLjMsICJjbSIpLAogICAgICAgIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSA2LjUpLAogICAgICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gNykpCgpwZGYoImZpZ3VyZV9wYW5lbHNfcmV2MS9maWdfY2lyL2VuZG9fc2lnX3Zpby5wZGYiLCBoZWlnaHQgPSAyLjgsIHdpZHRoID0gMTEpCnByaW50KHBsdCkKZGV2Lm9mZigpCmBgYAoKSGVwYXRvY3l0ZSBzaWduYXR1cmVzCgpgYGB7cn0Kc2NvcmVzX2RmID0gcmVhZFJEUygicmVzdWx0cy9jaXJyaG9zaXMvZHNfaGVwX3Njb3JlZERldl9kZi5SRFMiKQpzY29yZXNfZGYkQ29uZGl0aW9uW3Njb3Jlc19kZiRDb25kaXRpb249PSJlbWJvbGlzZWQiXSA9ICJlbWJvbGl6ZWQiCgpwbHQgPSBnZ3Bsb3Qoc2NvcmVzX2RmLCBhZXMoeCA9IGNpcnJfZmV0YWxfMywgeSA9IGNpcnJfZmV0YWxfNiwgY29sb3VyID0gQ29uZGl0aW9uKSkrCiAgZmFjZXRfd3JhcCh+c3VicG9wcykrCiAgZ2VvbV9kZW5zaXR5XzJkKHNpemUgPSAwLjMpKwogIHNjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzID0gY29sY29uZCwgZHJvcCA9IFQsIGxpbWl0cyA9IG5hbWVzKGNvbGNvbmQpW2MoMSwyLDQpXSkrCiAgbGFicyh4ID0gIkFkdWx0IGhlcGF0b2N5dGUgc2lnbmF0dXJlIiwgeSA9ICJGZXRhbCBoZXBhdG9jeXRlIHNpZ25hdHVyZSIpKwogIHRoZW1lX2NsYXNzaWMoKSsKICB0aGVtZShhc3BlY3QucmF0aW8gPSAxLAogICAgICAgIGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dChjb2xvdXIgPSAiYmxhY2siLCBzaXplID0gNiksCiAgICAgICAgYXhpcy50aXRsZSA9IGVsZW1lbnRfdGV4dChjb2xvdXIgPSAiYmxhY2siLCBzaXplID0gNiksCiAgICAgICAgc3RyaXAudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gNyksCiAgICAgICAgbGVnZW5kLmtleS5zaXplID0gdW5pdCgwLjMsICJjbSIpLAogICAgICAgIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSA2LjUpLAogICAgICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gNykpCgpwZGYoImZpZ3VyZV9wYW5lbHNfcmV2MS9maWdfY2lyL2hlcF9kZXZfc2lnX2RlbnNpdHkucGRmIiwgaGVpZ2h0ID0gMS41LCB3aWR0aCA9IDQuNSkKcHJpbnQocGx0KQpkZXYub2ZmKCkKYGBgCgoKCgo=